summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhong Wang <Zhong.Wang@Sun.COM>2009-03-19 03:03:46 +0800
committerZhong Wang <Zhong.Wang@Sun.COM>2009-03-19 03:03:46 +0800
commit2a8164df8a5f42c8a00f10c67d7bc84f80ae9c41 (patch)
tree5ef9c65f09194743324b20261093e076d4eeea6b
parentbfe6f8f50e1ad7cfc72f4665989dc9e25e82e872 (diff)
downloadillumos-joyent-2a8164df8a5f42c8a00f10c67d7bc84f80ae9c41.tar.gz
PSARC/2008/310 FCoE (Fibre Channel over Ethernet) Target
6701027 Need FCoE target for Solaris 6812750 Change in stmf/fct/stmf_sbd needed for support FCoE
-rw-r--r--usr/src/Makefile.lint3
-rw-r--r--usr/src/cmd/fcinfo/Makefile14
-rw-r--r--usr/src/cmd/fcinfo/fcinfo-list.c20
-rw-r--r--usr/src/cmd/fcinfo/fcinfo.c74
-rw-r--r--usr/src/cmd/fcinfo/fcinfo.h33
-rw-r--r--usr/src/cmd/fcinfo/fcoe_config.xml94
-rw-r--r--usr/src/cmd/fcinfo/fcoeadm.c949
-rw-r--r--usr/src/cmd/fcinfo/fcoeconfig35
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libfcoe/Makefile55
-rw-r--r--usr/src/lib/libfcoe/Makefile.com53
-rw-r--r--usr/src/lib/libfcoe/amd64/Makefile32
-rw-r--r--usr/src/lib/libfcoe/common/libfcoe.c347
-rw-r--r--usr/src/lib/libfcoe/common/libfcoe.h120
-rw-r--r--usr/src/lib/libfcoe/common/llib-lfcoe29
-rw-r--r--usr/src/lib/libfcoe/common/mapfile-vers48
-rw-r--r--usr/src/lib/libfcoe/i386/Makefile31
-rw-r--r--usr/src/lib/libfcoe/sparc/Makefile29
-rw-r--r--usr/src/lib/libfcoe/sparcv9/Makefile34
-rw-r--r--usr/src/pkgdefs/Makefile3
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/Makefile33
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/depend50
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl50
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/postinstall54
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/preremove33
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/prototype_com41
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/prototype_i38653
-rw-r--r--usr/src/pkgdefs/SUNWfcoe/prototype_sparc52
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/Makefile33
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/depend52
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl50
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/postinstall54
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/preremove33
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/prototype_com41
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/prototype_i38652
-rw-r--r--usr/src/pkgdefs/SUNWfcoet/prototype_sparc51
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/Makefile34
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/depend50
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl48
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/prototype_com45
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/prototype_i38648
-rw-r--r--usr/src/pkgdefs/SUNWfcoeu/prototype_sparc47
-rw-r--r--usr/src/pkgdefs/SUNWfcprt/depend3
-rw-r--r--usr/src/pkgdefs/SUNWfcprtr/preremove23
-rw-r--r--usr/src/pkgdefs/SUNWfcprtr/prototype_com4
-rw-r--r--usr/src/tools/scripts/bfu.sh2
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/Makefile.rules15
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c33
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet.c1035
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet.h307
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c1187
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h46
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c1053
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h65
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/discovery.c12
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/fct.c7
-rw-r--r--usr/src/uts/common/io/comstar/stmf/stmf.c17
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe.c1286
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe.conf35
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe.h249
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_eth.c373
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_eth.h45
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_fc.c490
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_fc.h47
-rw-r--r--usr/src/uts/common/sys/ethernet.h5
-rw-r--r--usr/src/uts/common/sys/fcoe/fcoe_common.h349
-rw-r--r--usr/src/uts/common/sys/fcoe/fcoeio.h144
-rw-r--r--usr/src/uts/common/sys/fct.h3
-rw-r--r--usr/src/uts/common/sys/stmf.h3
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared2
-rw-r--r--usr/src/uts/intel/fcoe/Makefile85
-rw-r--r--usr/src/uts/intel/fcoet/Makefile86
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/fcoe/Makefile85
-rw-r--r--usr/src/uts/sparc/fcoet/Makefile85
76 files changed, 10164 insertions, 32 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 635ce2f6d9..cde949e045 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -20,7 +20,7 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -356,6 +356,7 @@ COMMON_SUBDIRS = \
lib/libefi \
lib/libelfsign \
lib/libexacct \
+ lib/libfcoe \
lib/libgen \
lib/libgss \
lib/libidmap \
diff --git a/usr/src/cmd/fcinfo/Makefile b/usr/src/cmd/fcinfo/Makefile
index d625bde799..814e952fd5 100644
--- a/usr/src/cmd/fcinfo/Makefile
+++ b/usr/src/cmd/fcinfo/Makefile
@@ -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.
#
#
@@ -30,12 +30,14 @@ COMMONBASE = ../../common
PROG = fcinfo
ROOT_PROG_LINK = $(ROOTUSRSBIN)/fcadm
MANIFEST = npiv_config.xml
+MANIFEST += fcoe_config.xml
SVCMETHOD = npivconfig
+SVCMETHOD += fcoeconfig
PRODUCT = $(PROG)
$(ROOT_PROG_LINK) := FILEMODE = 0555
-LOCAL_OBJS = fcinfo.o fcinfo-list.o fcadm-list.o printAttrs.o
+LOCAL_OBJS = fcinfo.o fcinfo-list.o fcadm-list.o printAttrs.o fcoeadm.o
COMMON_OBJS = cmdparse.o
LOCAL_SRCS = $(LOCAL_OBJS:%.o=%.c)
COMMON_SRCS = $(COMMON_OBJS:%.o=$(COMMONBASE)/cmdparse/%.c)
@@ -44,14 +46,19 @@ SRCS = $(LOCAL_SRCS) $(COMMON_SRCS)
include ../Makefile.cmd
+POFILE = fcinfo_cmd.po
+POFILES = fcinfo.po fcinfo-list.po fcadm-list.po printAttrs.po fcoeadm.po
+
ROOTMANIFESTDIR= $(ROOTSVCNETWORK)
LDLIBS += -lHBAAPI
+LDLIBS += -lfcoe
LDLIBS += -lscf
INCS += -I.
INCS += -I$(SRC)/lib/hbaapi/common
INCS += -I$(COMMONBASE)/cmdparse
+INCS += -I$(SRC)/lib/libfcoe/common
CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -D_REENTRANT $(INCS)
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
@@ -81,6 +88,9 @@ install: all $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTUSRSBINPROG) $(ROOT_PROG_LIN
cmdparse.o: $(COMMONBASE)/cmdparse/cmdparse.c
$(COMPILE.c) -o $@ $(COMMONBASE)/cmdparse/cmdparse.c
$(POST_PROCESS_O)
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
clean:
$(RM) $(OBJS)
diff --git a/usr/src/cmd/fcinfo/fcinfo-list.c b/usr/src/cmd/fcinfo/fcinfo-list.c
index 5b33cf449b..2030441d44 100644
--- a/usr/src/cmd/fcinfo/fcinfo-list.c
+++ b/usr/src/cmd/fcinfo/fcinfo-list.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.
*/
@@ -377,6 +377,10 @@ processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex,
int discPortCount;
if (resourceType == HBA_PORT) {
+ if ((flags & PRINT_FCOE) == PRINT_FCOE &&
+ attrs.VendorSpecificID != 0xFC0E) {
+ return (0);
+ }
printHBAPortInfo(&port, &attrs, mode);
if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
printLinkStat(handle, port.PortWWN, port.PortWWN);
@@ -736,6 +740,8 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
processHBA_flags |= PRINT_INITIATOR;
} else if (options->optval == 't') {
processHBA_flags |= PRINT_TARGET;
+ } else if (options->optval == 'e') {
+ processHBA_flags |= PRINT_FCOE;
}
}
@@ -837,8 +843,9 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
}
processHBA(handle, attrs, portIndex, port, NULL,
HBA_PORT, processHBA_flags, mode);
- if (printHBANPIVPortInfo(handle, portIndex)
- != 0) {
+ if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE &&
+ attrs.VendorSpecificID != 0xFC0E &&
+ printHBANPIVPortInfo(handle, portIndex) != 0) {
err_cnt++;
}
HBA_CloseAdapter(handle);
@@ -920,8 +927,11 @@ fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
processHBA(handle, attrs, portIndex, port,
NULL, HBA_PORT, processHBA_flags,
INITIATOR_MODE);
- if (printHBANPIVPortInfo(handle, portIndex)
- != 0) {
+ if ((processHBA_flags & PRINT_FCOE) !=
+ PRINT_FCOE &&
+ attrs.VendorSpecificID != 0xFC0E &&
+ printHBANPIVPortInfo(handle,
+ portIndex) != 0) {
err_cnt++;
}
}
diff --git a/usr/src/cmd/fcinfo/fcinfo.c b/usr/src/cmd/fcinfo/fcinfo.c
index 9da68b8b06..396647d9fb 100644
--- a/usr/src/cmd/fcinfo/fcinfo.c
+++ b/usr/src/cmd/fcinfo/fcinfo.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.
*/
@@ -50,6 +50,10 @@ static int npivDeletePortFunc(int, char **, cmdOptions_t *, void *);
static int npivCreatePortListFunc(int, char **, cmdOptions_t *, void *);
static int npivListHbaPortFunc(int, char **, cmdOptions_t *, void *);
static int npivListRemotePortFunc(int, char **, cmdOptions_t *, void *);
+static int fcoeAdmCreatePortFunc(int, char **, cmdOptions_t *, void *);
+static int fcoeListPortsFunc(int, char **, cmdOptions_t *, void *);
+static int fcoeAdmDeletePortFunc(int, char **, cmdOptions_t *, void *);
+static int fcoeAdmCreatePortListFunc(int, char **, cmdOptions_t *, void *);
static char *getExecBasename(char *);
/*
@@ -63,6 +67,7 @@ optionTbl_t fcinfolongOptions[] = {
{"initiator", no_argument, 'i', NULL},
{"linkstat", no_argument, 'l', NULL},
{"scsi-target", no_argument, 's', NULL},
+ {"fcoe", no_argument, 'e', NULL},
{"verbose", no_argument, 'v', NULL},
{NULL, 0, 0}
};
@@ -72,6 +77,8 @@ optionTbl_t fcadmlongOptions[] = {
{"node", required_argument, 'n', OPTIONSTRING2},
{"linkstat", no_argument, 'l', NULL},
{"scsi-target", no_argument, 's', NULL},
+ {"fcoe-force-promisc", no_argument, 'f', NULL},
+ {"target", no_argument, 't', NULL},
{NULL, 0, 0}
};
@@ -79,7 +86,7 @@ optionTbl_t fcadmlongOptions[] = {
* Add new subcommands here
*/
subCommandProps_t fcinfosubcommands[] = {
- {"hba-port", listHbaPortFunc, "itl", NULL, NULL,
+ {"hba-port", listHbaPortFunc, "itel", NULL, NULL,
OPERAND_OPTIONAL_MULTIPLE, "WWN"},
{"remote-port", listRemotePortFunc, "lsp", "p", NULL,
OPERAND_OPTIONAL_MULTIPLE, "WWN"},
@@ -106,8 +113,21 @@ subCommandProps_t fcadmsubcommands[] = {
{"create-port-list",
npivCreatePortListFunc, NULL, NULL, NULL,
OPERAND_NONE, NULL},
+ {"create-fcoe-port",
+ fcoeAdmCreatePortFunc, "tpnf", "t", 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,
+ OPERAND_NONE, NULL},
+ {"create-fcoe-ports",
+ fcoeAdmCreatePortListFunc, "t", NULL, NULL,
+ OPERAND_NONE, NULL},
{NULL, 0, NULL, NULL, NULL, 0, NULL, NULL}
};
+
/*
* Pass in options/arguments, rest of arguments
*/
@@ -190,6 +210,50 @@ npivListRemotePortFunc(int objects, char *argv[],
}
/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+fcoeAdmCreatePortFunc(int objects, char *argv[], cmdOptions_t *options,
+ void *addArgs)
+{
+ return (fcoe_adm_create_port(objects, argv, options));
+}
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+fcoeAdmDeletePortFunc(int objects, char *argv[], cmdOptions_t *options,
+ void *addArgs)
+{
+ return (fcoe_adm_delete_port(objects, argv));
+}
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+fcoeListPortsFunc(int objects, char *argv[], cmdOptions_t *options,
+ void *addArgs)
+{
+ return (fcoe_adm_list_ports(options));
+}
+
+/*
+ * Pass in options/arguments, rest of arguments
+ */
+/*ARGSUSED*/
+static int
+fcoeAdmCreatePortListFunc(int objects, char *argv[], cmdOptions_t *options,
+ void *addArgs)
+{
+ return (fcoe_adm_create_portlist(options));
+}
+
+/*
* input:
* execFullName - exec name of program (argv[0])
*
@@ -246,6 +310,12 @@ main(int argc, char *argv[])
int funcRet;
void *subcommandArgs = NULL;
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
/* set global command name */
cmdName = getExecBasename(argv[0]);
diff --git a/usr/src/cmd/fcinfo/fcinfo.h b/usr/src/cmd/fcinfo/fcinfo.h
index 343c379de2..4047ccaf4b 100644
--- a/usr/src/cmd/fcinfo/fcinfo.h
+++ b/usr/src/cmd/fcinfo/fcinfo.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.
*/
@@ -44,6 +44,7 @@ extern "C" {
#include <netinet/in.h>
#include <inttypes.h>
#include <cmdparse.h>
+#include <locale.h>
#ifdef _BIG_ENDIAN
#define htonll(x) (x)
@@ -88,16 +89,39 @@ extern "C" {
#define NPIV_PG_NAME "npiv-port-list"
#define NPIV_PORT_LIST "port_list"
+#define FCOE_SCF_ADD 0
+#define FCOE_SCF_REMOVE 1
+
+#define FCOE_SUCCESS 0
+#define FCOE_ERROR 1
+#define FCOE_ERROR_NOT_FOUND 2
+#define FCOE_ERROR_EXISTS 3
+#define FCOE_ERROR_SERVICE_NOT_FOUND 4
+#define FCOE_ERROR_NOMEM 5
+#define FCOE_ERROR_MEMBER_NOT_FOUND 6
+#define FCOE_ERROR_BUSY 7
+
+#define FCOE_PORT_LIST_LENGTH 255
+
+#define FCOE_SERVICE "network/fcoe_config"
+#define FCOE_PG_NAME "fcoe-port-list-pg"
+#define FCOE_PORT_LIST "port_list_p"
+
/* flags that are needed to be passed into processHBA */
#define PRINT_LINKSTAT 0x00000001 /* print link statistics information */
#define PRINT_SCSI_TARGET 0x00000010 /* print Scsi target information */
#define PRINT_INITIATOR 0x00000100 /* print intiator port information */
#define PRINT_TARGET 0x00001000 /* print target port information */
+#define PRINT_FCOE 0x00010000 /* print fcoe port information */
/* flags for Adpater/port mode */
#define INITIATOR_MODE 0x00000001
#define TARGET_MODE 0x00000010
+/* FCOE */
+#define FCOE_MAX_MAC_NAME_LEN 32
+#define FCOE_USER_RAW_FRAME_SIZE 224
+
typedef struct _tgtPortWWNList {
HBA_WWN portWWN;
HBA_UINT32 scsiOSLun;
@@ -142,6 +166,13 @@ int fc_util_delete_npivport(int wwnCount, char **argv, cmdOptions_t *options);
int fc_util_create_npivport(int wwnCount, char **argv, cmdOptions_t *options);
int fc_util_create_portlist();
+int fcoe_adm_create_port(int objects, char *argv[],
+ cmdOptions_t *options);
+int fcoe_adm_delete_port(int objects, char *argv[]);
+int fcoe_adm_list_ports(cmdOptions_t *options);
+int fcoe_adm_create_portlist(cmdOptions_t *options);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/fcinfo/fcoe_config.xml b/usr/src/cmd/fcinfo/fcoe_config.xml
new file mode 100644
index 0000000000..10dcbc4f60
--- /dev/null
+++ b/usr/src/cmd/fcinfo/fcoe_config.xml
@@ -0,0 +1,94 @@
+<?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 configure
+
+
+-->
+
+<!--
+
+-->
+
+<service_bundle type='manifest' name='SUNWfcprt:fcoe_config'>
+
+<service
+ name='network/fcoe_config'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='true' />
+
+ <single_instance/>
+
+ <dependency
+ name='fcoesysevent'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/sysevent' />
+ </dependency>
+
+ <dependent
+ name='fcoe-filesystem'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/filesystem/local' />
+ </dependent>
+
+ <dependent
+ name='fcoe-fc'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/device/fc-fabric' />
+ </dependent>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/fcoeconfig'
+ timeout_seconds='1200'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':true'
+ timeout_seconds='60'>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring'
+ value='transient' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/fcinfo/fcoeadm.c b/usr/src/cmd/fcinfo/fcoeadm.c
new file mode 100644
index 0000000000..340d33dfa9
--- /dev/null
+++ b/usr/src/cmd/fcinfo/fcoeadm.c
@@ -0,0 +1,949 @@
+/*
+ * 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 "fcinfo.h"
+#include <libintl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/list.h>
+#include <stddef.h>
+#include <strings.h>
+#include <libfcoe.h>
+#include <libscf.h>
+#include <syslog.h>
+
+static const char *FCOE_DRIVER_PATH = "/devices/fcoe:admin";
+
+static char *
+WWN2str(char *buf, FCOE_PORT_WWN *wwn) {
+ int j;
+ unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
+ buf[0] = '\0';
+ for (j = 0; j < 16; j += 2) {
+ sprintf(&buf[j], "%02X", (int)*pc++);
+ }
+ return (buf);
+}
+
+static int
+isValidWWN(char *wwn)
+{
+ int index;
+
+ if (wwn == NULL) {
+ return (0);
+ }
+
+ if (strlen(wwn) != 16) {
+ return (0);
+ }
+
+ for (index = 0; index < 16; index++) {
+ if (isxdigit(wwn[index])) {
+ continue;
+ }
+ return (0);
+ }
+ return (1);
+}
+
+static uint64_t wwnconvert(uchar_t *wwn)
+{
+ uint64_t tmp;
+ memcpy(&tmp, wwn, sizeof (uint64_t));
+ return (ntohll(tmp));
+}
+
+/*
+ * prints out all the HBA port information
+ */
+void
+printFCOEPortInfo(FCOE_PORT_ATTRIBUTE *attr)
+{
+ int i;
+ if (attr == NULL) {
+ return;
+ }
+ fprintf(stdout, gettext("HBA Port WWN: %016llx\n"),
+ wwnconvert((unsigned char *)&attr->port_wwn));
+
+ fprintf(stdout, gettext("\tPort Type: %s\n"),
+ (attr->port_type == 0) ? "Initiator" : "Target");
+
+ fprintf(stdout, gettext("\tMAC Name: %s\n"), attr->mac_link_name);
+
+ fprintf(stdout, gettext("\tMTU Size: %d\n"), attr->mtu_size);
+
+ fprintf(stdout, gettext("\tMAC Factory Address: "));
+ for (i = 0; i < 6; i++) {
+ fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]);
+ }
+ fprintf(stdout, gettext("\n\tMAC Current Address: "));
+ for (i = 0; i < 6; i++) {
+ fprintf(stdout, gettext("%02x"), attr->mac_current_addr[i]);
+ }
+ fprintf(stdout, gettext("\n\tPromiscuous Mode: %s\n"),
+ attr->mac_promisc == 1 ? "On" : "Off");
+}
+
+/*
+ * Initialize scf fcoe service access
+ * handle - returned handle
+ * service - returned service handle
+ */
+static int
+fcoe_cfg_scf_init(scf_handle_t **handle, scf_service_t **service)
+{
+ scf_scope_t *scope = NULL;
+ int ret;
+
+ if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
+ syslog(LOG_ERR, "scf_handle_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_bind(*handle) == -1) {
+ syslog(LOG_ERR, "scf_handle_bind failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if ((*service = scf_service_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_service_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if ((scope = scf_scope_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_scope_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
+ syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto err;
+ }
+
+ if (scf_scope_get_service(scope, FCOE_SERVICE, *service) == -1) {
+ syslog(LOG_ERR, "scf_scope_get_service failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR_SERVICE_NOT_FOUND;
+ goto err;
+ }
+
+ scf_scope_destroy(scope);
+
+ return (FCOE_SUCCESS);
+
+err:
+ if (*handle != NULL) {
+ scf_handle_destroy(*handle);
+ }
+ if (*service != NULL) {
+ scf_service_destroy(*service);
+ *service = NULL;
+ }
+ if (scope != NULL) {
+ scf_scope_destroy(scope);
+ }
+ return (ret);
+}
+
+
+static int
+fcoe_adm_add_remove_scf_entry(char *mac_name,
+ char *pwwn, char *nwwn,
+ int is_target, int is_promiscuous, int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ scf_value_t **valueSet = NULL;
+ int ret = FCOE_SUCCESS;
+ boolean_t createProp = B_FALSE;
+ int lastAlloc = 0;
+ char buf[FCOE_PORT_LIST_LENGTH] = {0};
+ char memberName[FCOE_PORT_LIST_LENGTH] = {0};
+ boolean_t found = B_FALSE;
+ int i = 0;
+ int valueArraySize = 0;
+ int commitRet;
+
+ sprintf(memberName, "%s:%s:%s:%d:%d", mac_name, pwwn, nwwn,
+ is_target, is_promiscuous);
+
+ ret = fcoe_cfg_scf_init(&handle, &svc);
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ /* get property group or create it */
+ if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
+ if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
+ if (scf_service_add_pg(svc, FCOE_PG_NAME,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ } else {
+ createProp = B_TRUE;
+ }
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ }
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+ }
+
+ /* to make sure property exists */
+ if (createProp == B_FALSE) {
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ if ((scf_error() == SCF_ERROR_NOT_FOUND)) {
+ createProp = B_TRUE;
+ } else {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ /* Begin the transaction */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
+ * (lastAlloc = PORT_LIST_ALLOC));
+ if (valueSet == NULL) {
+ ret = FCOE_ERROR_NOMEM;
+ goto out;
+ }
+
+ if (createProp) {
+ if (scf_transaction_property_new(tran, entry, FCOE_PORT_LIST,
+ SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = FCOE_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ FCOE_PORT_LIST, SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ char *macnameIter = NULL;
+ char buftmp[FCOE_PORT_LIST_LENGTH] = {0};
+
+ bzero(buf, sizeof (buf));
+ if (scf_value_get_ustring(valueLookup,
+ buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+ strcpy(buftmp, buf);
+ macnameIter = strtok(buftmp, ":");
+ if (bcmp(macnameIter, mac_name,
+ strlen(mac_name)) == 0) {
+ if (addRemoveFlag == FCOE_SCF_ADD) {
+ ret = FCOE_ERROR_EXISTS;
+ break;
+ } else {
+ found = B_TRUE;
+ continue;
+ }
+ }
+
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ if (scf_value_set_ustring(valueSet[i], buf) == -1) {
+ syslog(LOG_ERR, "set value failed 1- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ break;
+ }
+
+ i++;
+
+ if (i >= lastAlloc) {
+ lastAlloc += PORT_LIST_ALLOC;
+ valueSet = realloc(valueSet,
+ sizeof (*valueSet) * lastAlloc);
+ if (valueSet == NULL) {
+ ret = FCOE_ERROR;
+ break;
+ }
+ }
+ }
+ }
+
+ valueArraySize = i;
+ if (!found && (addRemoveFlag == FCOE_SCF_REMOVE)) {
+ ret = FCOE_ERROR_MEMBER_NOT_FOUND;
+ }
+ if (ret != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (addRemoveFlag == FCOE_SCF_ADD) {
+ /*
+ * Now create the new entry
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ } else {
+ valueArraySize++;
+ }
+
+ /*
+ * Set the new member name
+ */
+ if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
+ syslog(LOG_ERR, "set value failed 2- %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the new member
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = FCOE_ERROR;
+ goto out;
+ }
+ }
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = FCOE_ERROR_BUSY;
+ } else {
+ ret = FCOE_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+
+ /*
+ * Free valueSet scf resources
+ */
+ if (valueArraySize > 0) {
+ for (i = 0; i < valueArraySize; i++) {
+ scf_value_destroy(valueSet[i]);
+ }
+ }
+ /*
+ * Now free the pointer array to the resources
+ */
+ if (valueSet != NULL) {
+ free(valueSet);
+ }
+
+ return (ret);
+}
+
+int
+fcoe_adm_create_port(int objects, char *argv[],
+ cmdOptions_t *options)
+{
+ FCOE_STATUS status = FCOE_STATUS_OK;
+ uint64_t nodeWWN, portWWN;
+ FCOE_PORT_WWN pwwn, nwwn;
+ FCOE_UINT8 macLinkName[FCOE_MAX_MAC_NAME_LEN];
+ FCOE_UINT8 promiscuous = 0;
+ int createini = 0, createtgt = 0;
+
+ /* check the mac name operand */
+ assert(objects == 1);
+
+ strcpy((char *)macLinkName, argv[0]);
+ bzero(&pwwn, 8);
+ bzero(&nwwn, 8);
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'i':
+ createini = 1;
+ break;
+
+ case 't':
+ createtgt = 1;
+ break;
+ case 'p':
+ if (!isValidWWN(options->optarg)) {
+ fprintf(stderr,
+ gettext("Error: Invalid Port WWN\n"));
+ return (1);
+ }
+ sscanf(options->optarg, "%016llx", &portWWN);
+ portWWN = htonll(portWWN);
+ memcpy(&pwwn, &portWWN, sizeof (portWWN));
+ break;
+
+ case 'n':
+ if (!isValidWWN(options->optarg)) {
+ fprintf(stderr,
+ gettext("Error: Invalid Node WWN\n"));
+ return (1);
+ }
+ sscanf(options->optarg, "%016llx", &nodeWWN);
+ nodeWWN = htonll(nodeWWN);
+ memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
+ break;
+ case 'f':
+ promiscuous = 1;
+ break;
+
+ default:
+ fprintf(stderr, gettext("Error: Illegal option: %c\n"),
+ options->optval);
+ return (1);
+ }
+ }
+
+ if (createini == 1 && createtgt == 1) {
+ fprintf(stderr, "Error: Option -i and -t should "
+ "not be both specified\n");
+ return (1);
+ }
+ status = FCOE_CreatePort(macLinkName,
+ createtgt == 1 ? FCOE_PORTTYPE_TARGET :
+ FCOE_PORTTYPE_INITIATOR, pwwn, nwwn, promiscuous);
+
+ if (status != FCOE_STATUS_OK) {
+ switch (status) {
+ case FCOE_STATUS_ERROR_BUSY:
+ fprintf(stderr,
+ gettext("Error: fcoe driver is busy\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_ALREADY:
+ fprintf(stderr,
+ gettext("Error: Existing FCoE port "
+ "found on the specified MAC link\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_PERM:
+ fprintf(stderr,
+ gettext("Error: Not enough permission to "
+ "open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_OPEN_DEV:
+ fprintf(stderr,
+ gettext("Error: Failed to open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_WWN_SAME:
+ fprintf(stderr,
+ gettext("Error: Port WWN is same as Node "
+ "WWN\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_MAC_LEN:
+ fprintf(stderr,
+ gettext("Error: MAC name exceeds maximum "
+ "length\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_PWWN_CONFLICTED:
+ fprintf(stderr,
+ gettext("Error: The specified Port WWN "
+ "is already in use\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_NWWN_CONFLICTED:
+ fprintf(stderr,
+ gettext("Error: The specified Node WWN "
+ "is already in use\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_NEED_JUMBO_FRAME:
+ fprintf(stderr,
+ gettext("Error: MTU size of the specified "
+ "MAC link needs to be increased to 2500 "
+ "or above\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_CREATE_MAC:
+ fprintf(stderr,
+ gettext("Error: Out of memory\n"));
+ break;
+
+
+ case FCOE_STATUS_ERROR_OPEN_MAC:
+ fprintf(stderr,
+ gettext("Error: Failed to open the "
+ "specified MAC link\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_CREATE_PORT:
+ fprintf(stderr,
+ gettext("Error: Failed to create FCoE "
+ "port on the specified MAC link\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_VNIC_UNSUPPORT:
+ fprintf(stderr,
+ gettext("Error: VNIC is not supported\n"));
+ break;
+
+ case FCOE_STATUS_ERROR:
+ default:
+ fprintf(stderr,
+ gettext("Error: Due to reason code %d\n"), status);
+ }
+ return (1);
+ } else {
+ char cpwwn[17], cnwwn[17];
+
+ WWN2str(cpwwn, &pwwn);
+ WWN2str(cnwwn, &nwwn);
+
+ fcoe_adm_add_remove_scf_entry((char *)macLinkName,
+ cpwwn,
+ cnwwn,
+ createtgt,
+ promiscuous,
+ FCOE_SCF_ADD);
+ return (0);
+ }
+}
+
+int
+fcoe_adm_delete_port(int objects, char *argv[])
+{
+ FCOE_STATUS status;
+ FCOE_UINT8 *macLinkName;
+
+ /* check the mac name operand */
+ assert(objects == 1);
+
+ macLinkName = (FCOE_UINT8 *) argv[0];
+
+ status = FCOE_DeletePort(macLinkName);
+ if (status != FCOE_STATUS_OK) {
+ switch (status) {
+ case FCOE_STATUS_ERROR_BUSY:
+ fprintf(stderr,
+ gettext("Error: fcoe driver is busy\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_ALREADY:
+ fprintf(stderr,
+ gettext("Error: FCoE port not found on the "
+ "specified MAC link\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_PERM:
+ fprintf(stderr,
+ gettext("Error: Not enough permission to "
+ "open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_MAC_LEN:
+ fprintf(stderr,
+ gettext("Failed: MAC name exceeds maximum "
+ "length 32\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_OPEN_DEV:
+ fprintf(stderr,
+ gettext("Error: Failed to open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_MAC_NOT_FOUND:
+ fprintf(stderr,
+ gettext("Error: FCoE port not found on the "
+ "specified MAC link\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_OFFLINE_DEV:
+ fprintf(stderr,
+ gettext("Error: Please use stmfadm to offline "
+ "the FCoE target first\n"));
+ break;
+
+ case FCOE_STATUS_ERROR:
+ default:
+ fprintf(stderr,
+ gettext("Error: Due to reason code %d\n"), status);
+ }
+ return (1);
+ } else {
+ fcoe_adm_add_remove_scf_entry((char *)macLinkName,
+ "",
+ "",
+ 0,
+ 0,
+ FCOE_SCF_REMOVE);
+ return (0);
+ }
+}
+
+int
+fcoe_adm_list_ports(cmdOptions_t *options)
+{
+ FCOE_STATUS status;
+ int showini = 0, showtgt = 0;
+ FCOE_UINT32 port_num;
+ FCOE_PORT_ATTRIBUTE *portlist = NULL;
+ int i;
+ int ret;
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'i':
+ showini = 1;
+ break;
+
+ case 't':
+ showtgt = 1;
+ break;
+
+ default:
+ fprintf(stderr, gettext("Error: Illegal option: %c\n"),
+ options->optval);
+ return (1);
+ }
+ }
+ if (showini == 0 && showtgt == 0) {
+ showini = 1;
+ showtgt = 1;
+ }
+
+ status = FCOE_GetPortList(&port_num, &portlist);
+
+ if (status != FCOE_STATUS_OK) {
+ switch (status) {
+ case FCOE_STATUS_ERROR_BUSY:
+ fprintf(stderr,
+ gettext("Error: fcoe driver is busy\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_PERM:
+ fprintf(stderr,
+ gettext("Error: Not enough permission to "
+ "open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_OPEN_DEV:
+ fprintf(stderr,
+ gettext("Error: Failed to open fcoe device\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_INVAL_ARG:
+ fprintf(stderr,
+ gettext("Error: Invalid argument\n"));
+ break;
+
+ case FCOE_STATUS_ERROR_MORE_DATA:
+ fprintf(stderr,
+ gettext("Error: More data\n"));
+ break;
+
+ case FCOE_STATUS_ERROR:
+ default:
+ fprintf(stderr,
+ gettext("Error: Due to reason code %d\n"), status);
+ }
+ ret = 1;
+ } else {
+ if (port_num == 0) {
+ fprintf(stdout, gettext("No FCoE Ports Found!\n"));
+ } else {
+ for (i = 0; i < port_num; i++) {
+ if ((portlist[i].port_type ==
+ FCOE_PORTTYPE_INITIATOR &&
+ showini == 1) || (showtgt == 1 &&
+ portlist[i].port_type ==
+ FCOE_PORTTYPE_TARGET)) {
+ printFCOEPortInfo(&portlist[i]);
+ }
+ }
+ }
+ ret = 0;
+ }
+
+ if (portlist != NULL) {
+ free(portlist);
+ }
+ return (ret);
+
+}
+
+int
+fcoe_adm_create_portlist(cmdOptions_t *options)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ char buf[FCOE_PORT_LIST_LENGTH] = {0};
+ int commitRet;
+ int create_target = 0, create_initiator = 0;
+
+ /* Check what type of port list will be created */
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'i':
+ create_initiator = 1;
+ break;
+ case 't':
+ create_target = 1;
+ break;
+ default:
+ fprintf(stderr, gettext("Error: Illegal option: %c\n"),
+ options->optval);
+ return (1);
+ }
+ }
+
+ if (create_initiator == 0 && create_target == 0) {
+ create_initiator = 1;
+ create_target = 1;
+ }
+
+ commitRet = fcoe_cfg_scf_init(&handle, &svc);
+ if (commitRet != FCOE_SUCCESS) {
+ goto out;
+ }
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ goto out;
+ }
+
+ /* get property group or create it */
+ if (scf_service_get_pg(svc, FCOE_PG_NAME, pg) == -1) {
+ goto out;
+ }
+
+ if (scf_pg_get_property(pg, FCOE_PORT_LIST, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ goto out;
+ }
+
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ goto out;
+ }
+
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ goto out;
+ }
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ uint8_t *macLinkName = NULL;
+ char *remainder = NULL;
+ FCOE_PORT_WWN pwwn, nwwn;
+ uint64_t nodeWWN, portWWN;
+ int is_target, is_promiscuous;
+
+ bzero(buf, sizeof (buf));
+ bzero(&pwwn, sizeof (pwwn));
+ bzero(&nwwn, sizeof (nwwn));
+ if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ break;
+ }
+ macLinkName = (uint8_t *)strtok(buf, ":");
+ remainder = strtok(NULL, "#");
+ sscanf(remainder, "%016llx:%016llx:%d:%d",
+ &portWWN, &nodeWWN, &is_target, &is_promiscuous);
+ if ((!create_target && is_target) ||
+ (!create_initiator && !is_target)) {
+ continue;
+ }
+
+ nodeWWN = htonll(nodeWWN);
+ memcpy(&nwwn, &nodeWWN, sizeof (nodeWWN));
+ portWWN = htonll(portWWN);
+ memcpy(&pwwn, &portWWN, sizeof (portWWN));
+
+ FCOE_CreatePort(macLinkName,
+ is_target ? FCOE_PORTTYPE_TARGET : FCOE_PORTTYPE_INITIATOR,
+ pwwn, nwwn, is_promiscuous);
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/fcinfo/fcoeconfig b/usr/src/cmd/fcinfo/fcoeconfig
new file mode 100644
index 0000000000..ba47b22c69
--- /dev/null
+++ b/usr/src/cmd/fcinfo/fcoeconfig
@@ -0,0 +1,35 @@
+#!/sbin/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.
+#
+#
+# This script is used to reconfigure fabric device(s) which were configured
+# prior to boot. The luxadm command used below is an expert level command
+# and has a restrictive usage for boot time reconfiguration of fabric
+# devices.
+#
+# DO NOT USE the command for any other purpose.
+#
+
+/usr/sbin/fcadm create-fcoe-ports
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 2ec74c85d6..4dc4077d5a 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -152,6 +152,7 @@ SUBDIRS += \
libkrb5 .WAIT \
krb5 .WAIT \
libsmbfs \
+ libfcoe \
libstmf \
libnsctl \
libunistat \
@@ -430,6 +431,7 @@ HDRSUBDIRS= \
libslp \
libsmedia \
libsqlite \
+ libfcoe \
libstmf \
libsum \
libsysevent \
diff --git a/usr/src/lib/libfcoe/Makefile b/usr/src/lib/libfcoe/Makefile
new file mode 100644
index 0000000000..e9b7036a1f
--- /dev/null
+++ b/usr/src/lib/libfcoe/Makefile
@@ -0,0 +1,55 @@
+#
+# 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.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+install_h := TARGET= install_h
+lint := TARGET= lint
+
+
+HDRS= libfcoe.h
+HDRDIR= common
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libfcoe/Makefile.com b/usr/src/lib/libfcoe/Makefile.com
new file mode 100644
index 0000000000..8fd5bfd695
--- /dev/null
+++ b/usr/src/lib/libfcoe/Makefile.com
@@ -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.
+#
+
+LIBRARY= libfcoe.a
+VERS= .1
+
+OBJECTS= libfcoe.o
+
+include ../../Makefile.lib
+
+LIBS= $(DYNLIB) $(LINTLIB)
+
+SRCDIR = ../common
+
+INCS += -I$(SRCDIR)
+INCS += -I$(SRC)/uts/common/sys/fcoe
+
+LDLIBS += -lc
+C99MODE= -xc99=%all
+C99LMODE= -Xc99=%all
+CPPFLAGS += $(INCS) -D_REENTRANT
+
+$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libfcoe/amd64/Makefile b/usr/src/lib/libfcoe/amd64/Makefile
new file mode 100644
index 0000000000..9e8a127855
--- /dev/null
+++ b/usr/src/lib/libfcoe/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# 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
+include ../../Makefile.lib.64
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT)
diff --git a/usr/src/lib/libfcoe/common/libfcoe.c b/usr/src/lib/libfcoe/common/libfcoe.c
new file mode 100644
index 0000000000..f06a620f26
--- /dev/null
+++ b/usr/src/lib/libfcoe/common/libfcoe.c
@@ -0,0 +1,347 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <syslog.h>
+#include <libfcoe.h>
+#include <fcoeio.h>
+
+#define FCOE_DEV_PATH "/devices/fcoe:admin"
+
+#define OPEN_FCOE 0
+#define OPEN_EXCL_FCOE O_EXCL
+
+/*
+ * Open for fcoe module
+ *
+ * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE)
+ * fd - pointer to integer. On success, contains the fcoe file descriptor
+ */
+static int
+openFcoe(int flag, int *fd)
+{
+ int ret = FCOE_STATUS_ERROR;
+
+ if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = FCOE_STATUS_OK;
+ } else {
+ if (errno == EPERM || errno == EACCES) {
+ ret = FCOE_STATUS_ERROR_PERM;
+ } else {
+ ret = FCOE_STATUS_ERROR_OPEN_DEV;
+ }
+ syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)",
+ FCOE_DEV_PATH, errno);
+ }
+
+ return (ret);
+}
+
+static int
+isWWNZero(FCOE_PORT_WWN portwwn)
+{
+ int i;
+ int size = sizeof (FCOE_PORT_WWN);
+
+ for (i = 0; i < size; i++) {
+ if (portwwn.wwn[i] != 0) {
+ return (0);
+ }
+ }
+ return (1);
+}
+
+FCOE_STATUS
+FCOE_CreatePort(
+ const FCOE_UINT8 *macLinkName,
+ FCOE_UINT8 portType,
+ FCOE_PORT_WWN pwwn,
+ FCOE_PORT_WWN nwwn,
+ FCOE_UINT8 promiscuous)
+{
+ FCOE_STATUS status = FCOE_STATUS_OK;
+ int fcoe_fd;
+ fcoeio_t fcoeio;
+ fcoeio_create_port_param_t param;
+
+ bzero(&param, sizeof (fcoeio_create_port_param_t));
+
+ if (macLinkName == NULL) {
+ return (FCOE_STATUS_ERROR_INVAL_ARG);
+ }
+
+ if (portType != FCOE_PORTTYPE_INITIATOR &&
+ portType != FCOE_PORTTYPE_TARGET) {
+ return (FCOE_STATUS_ERROR_INVAL_ARG);
+ }
+
+ if (!isWWNZero(pwwn)) {
+ param.fcp_pwwn_provided = 1;
+ bcopy(pwwn.wwn, param.fcp_pwwn, 8);
+ }
+
+ if (!isWWNZero(nwwn)) {
+ param.fcp_nwwn_provided = 1;
+ bcopy(nwwn.wwn, param.fcp_nwwn, 8);
+ }
+
+ if (param.fcp_pwwn_provided == 1 &&
+ param.fcp_nwwn_provided == 1 &&
+ bcmp(&pwwn, &nwwn, 8) == 0) {
+ return (FCOE_STATUS_ERROR_WWN_SAME);
+ }
+
+ if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) {
+ return (FCOE_STATUS_ERROR_MAC_LEN);
+ }
+
+ param.fcp_force_promisc = promiscuous;
+ (void) strcpy((char *)param.fcp_mac_name, (char *)macLinkName);
+ param.fcp_port_type = (fcoe_cli_type_t)portType;
+
+ if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
+ return (status);
+ }
+
+ (void) memset(&fcoeio, 0, sizeof (fcoeio));
+ fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT;
+
+ fcoeio.fcoeio_ilen = sizeof (param);
+ fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
+ fcoeio.fcoeio_ibuf = (uintptr_t)&param;
+
+ if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
+ switch (fcoeio.fcoeio_status) {
+ case FCOEIOE_INVAL_ARG:
+ status = FCOE_STATUS_ERROR_INVAL_ARG;
+ break;
+
+ case FCOEIOE_BUSY:
+ status = FCOE_STATUS_ERROR_BUSY;
+ break;
+
+ case FCOEIOE_ALREADY:
+ status = FCOE_STATUS_ERROR_ALREADY;
+ break;
+
+ case FCOEIOE_PWWN_CONFLICTED:
+ status = FCOE_STATUS_ERROR_PWWN_CONFLICTED;
+ break;
+
+ case FCOEIOE_NWWN_CONFLICTED:
+ status = FCOE_STATUS_ERROR_NWWN_CONFLICTED;
+ break;
+
+ case FCOEIOE_CREATE_MAC:
+ status = FCOE_STATUS_ERROR_CREATE_MAC;
+ break;
+
+ case FCOEIOE_OPEN_MAC:
+ status = FCOE_STATUS_ERROR_OPEN_MAC;
+ break;
+
+ case FCOEIOE_CREATE_PORT:
+ status = FCOE_STATUS_ERROR_CREATE_PORT;
+ break;
+
+ case FCOEIOE_NEED_JUMBO_FRAME:
+ status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME;
+ break;
+
+ case FCOEIOE_VNIC_UNSUPPORT:
+ status = FCOE_STATUS_ERROR_VNIC_UNSUPPORT;
+ break;
+
+ default:
+ status = FCOE_STATUS_ERROR;
+ }
+ } else {
+ status = FCOE_STATUS_OK;
+ }
+ (void) close(fcoe_fd);
+ return (status);
+}
+
+FCOE_STATUS
+FCOE_DeletePort(const FCOE_UINT8 *macLinkName)
+{
+ FCOE_STATUS status = FCOE_STATUS_OK;
+ int fcoe_fd;
+ fcoeio_t fcoeio;
+
+ if (macLinkName == NULL) {
+ return (FCOE_STATUS_ERROR_INVAL_ARG);
+ }
+
+ if (strlen((char *)macLinkName) > FCOE_MAX_MAC_NAME_LEN-1) {
+ return (FCOE_STATUS_ERROR_MAC_LEN);
+ }
+
+ if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
+ return (status);
+ }
+
+ (void) memset(&fcoeio, 0, sizeof (fcoeio));
+ fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT;
+
+ fcoeio.fcoeio_ilen = strlen((char *)macLinkName)+1;
+ fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE;
+ fcoeio.fcoeio_ibuf = (uintptr_t)macLinkName;
+
+ if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
+ switch (fcoeio.fcoeio_status) {
+ case FCOEIOE_INVAL_ARG:
+ status = FCOE_STATUS_ERROR_INVAL_ARG;
+ break;
+
+ case FCOEIOE_BUSY:
+ status = FCOE_STATUS_ERROR_BUSY;
+ break;
+
+ case FCOEIOE_ALREADY:
+ status = FCOE_STATUS_ERROR_ALREADY;
+ break;
+
+ case FCOEIOE_MAC_NOT_FOUND:
+ status = FCOE_STATUS_ERROR_MAC_NOT_FOUND;
+ break;
+
+ case FCOEIOE_OFFLINE_FAILURE:
+ status = FCOE_STATUS_ERROR_OFFLINE_DEV;
+ break;
+
+ default:
+ status = FCOE_STATUS_ERROR;
+ }
+ } else {
+ status = FCOE_STATUS_OK;
+ }
+ (void) close(fcoe_fd);
+ return (status);
+}
+
+FCOE_STATUS
+FCOE_GetPortList(
+ FCOE_UINT32 *port_num,
+ FCOE_PORT_ATTRIBUTE **portlist)
+{
+ FCOE_STATUS status = FCOE_STATUS_OK;
+ int fcoe_fd;
+ fcoeio_t fcoeio;
+ fcoe_port_list_t *inportlist = NULL;
+ FCOE_PORT_ATTRIBUTE *outportlist = NULL;
+ int i;
+ int size = 64; /* default first attempt */
+ int retry = 0;
+ int bufsize;
+
+ if (port_num == NULL || portlist == NULL) {
+ return (FCOE_STATUS_ERROR_INVAL_ARG);
+ }
+ *port_num = 0;
+
+ if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) {
+ return (status);
+ }
+
+ /* Get fcoe port list */
+ (void) memset(&fcoeio, 0, sizeof (fcoeio));
+ retry = 0;
+
+ do {
+ bufsize = sizeof (fcoe_port_instance_t) * (size - 1) +
+ sizeof (fcoe_port_list_t);
+ inportlist = (fcoe_port_list_t *)malloc(bufsize);
+ fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST;
+ fcoeio.fcoeio_olen = bufsize;
+ fcoeio.fcoeio_xfer = FCOEIO_XFER_READ;
+ fcoeio.fcoeio_obuf = (uintptr_t)inportlist;
+
+ if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) {
+ if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) {
+ size = inportlist->numPorts;
+ }
+ free(inportlist);
+ switch (fcoeio.fcoeio_status) {
+ case FCOEIOE_INVAL_ARG:
+ status = FCOE_STATUS_ERROR_INVAL_ARG;
+ (void) close(fcoe_fd);
+ return (status);
+
+ case FCOEIOE_BUSY:
+ status = FCOE_STATUS_ERROR_BUSY;
+ retry++;
+ break;
+
+ case FCOEIOE_MORE_DATA:
+ status = FCOE_STATUS_ERROR_MORE_DATA;
+ retry++;
+ default:
+ status = FCOE_STATUS_ERROR;
+ }
+ } else {
+ status = FCOE_STATUS_OK;
+ break;
+ }
+ } while (retry <= 3 && status != FCOE_STATUS_OK);
+
+ if (status == FCOE_STATUS_OK) {
+ outportlist = (PFCOE_PORT_ATTRIBUTE)
+ malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts);
+
+ for (i = 0; i < inportlist->numPorts; i++) {
+ fcoe_port_instance_t *pi = &inportlist->ports[i];
+ FCOE_PORT_ATTRIBUTE *po = &outportlist[i];
+ bcopy(pi->fpi_pwwn, &po->port_wwn, 8);
+ bcopy(pi->fpi_mac_link_name, po->mac_link_name, 32);
+ bcopy(pi->fpi_mac_factory_addr,
+ po->mac_factory_addr, 6);
+ bcopy(pi->fpi_mac_current_addr,
+ po->mac_current_addr, 6);
+ po->port_type = (FCOE_UINT8)pi->fpi_port_type;
+ po->mtu_size = pi->fpi_mtu_size;
+ po->mac_promisc = pi->fpi_mac_promisc;
+ }
+ *port_num = inportlist->numPorts;
+ *portlist = outportlist;
+ free(inportlist);
+ } else {
+ *port_num = 0;
+ *portlist = NULL;
+ }
+ (void) close(fcoe_fd);
+ return (status);
+}
diff --git a/usr/src/lib/libfcoe/common/libfcoe.h b/usr/src/lib/libfcoe/common/libfcoe.h
new file mode 100644
index 0000000000..30570205a7
--- /dev/null
+++ b/usr/src/lib/libfcoe/common/libfcoe.h
@@ -0,0 +1,120 @@
+/*
+ * 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 _LIBFCOE_H
+#define _LIBFCOE_H
+
+#include <time.h>
+#include <wchar.h>
+#include <sys/param.h>
+#include <sys/ethernet.h>
+#include <libnvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * FCOE Port Type
+ */
+#define FCOE_PORTTYPE_INITIATOR 0
+#define FCOE_PORTTYPE_TARGET 1
+
+#define FCOE_MAX_MAC_NAME_LEN 32
+typedef unsigned char FCOE_UINT8;
+typedef char FCOE_INT8;
+typedef unsigned short FCOE_UINT16;
+typedef short FCOE_INT16;
+typedef unsigned int FCOE_UINT32;
+typedef int FCOE_INT32;
+
+typedef unsigned int FCOE_STATUS;
+
+#define FCOE_STATUS_OK 0
+#define FCOE_STATUS_ERROR 1
+#define FCOE_STATUS_ERROR_INVAL_ARG 2
+#define FCOE_STATUS_ERROR_BUSY 3
+#define FCOE_STATUS_ERROR_ALREADY 4
+#define FCOE_STATUS_ERROR_PERM 5
+#define FCOE_STATUS_ERROR_OPEN_DEV 6
+#define FCOE_STATUS_ERROR_WWN_SAME 7
+#define FCOE_STATUS_ERROR_MAC_LEN 8
+#define FCOE_STATUS_ERROR_PWWN_CONFLICTED 9
+#define FCOE_STATUS_ERROR_NWWN_CONFLICTED 10
+#define FCOE_STATUS_ERROR_NEED_JUMBO_FRAME 11
+#define FCOE_STATUS_ERROR_CREATE_MAC 12
+#define FCOE_STATUS_ERROR_OPEN_MAC 13
+#define FCOE_STATUS_ERROR_CREATE_PORT 14
+#define FCOE_STATUS_ERROR_MAC_NOT_FOUND 15
+#define FCOE_STATUS_ERROR_OFFLINE_DEV 16
+#define FCOE_STATUS_ERROR_MORE_DATA 17
+#define FCOE_STATUS_ERROR_VNIC_UNSUPPORT 18
+
+typedef struct fcoe_port_wwn {
+ uchar_t wwn[8];
+} FCOE_PORT_WWN, *PFCOE_PORT_WWN;
+
+typedef struct fcoe_port_attr {
+ FCOE_PORT_WWN port_wwn;
+ FCOE_UINT8 mac_link_name[MAXLINKNAMELEN];
+ FCOE_UINT8 mac_factory_addr[ETHERADDRL];
+ FCOE_UINT8 mac_current_addr[ETHERADDRL];
+ FCOE_UINT8 port_type;
+ FCOE_UINT32 mtu_size;
+ FCOE_UINT8 mac_promisc;
+} FCOE_PORT_ATTRIBUTE, *PFCOE_PORT_ATTRIBUTE;
+
+/*
+ * macLinkName: mac name with maximum lenth 32
+ * portType: 0 (Initiator)/ 1(Target)
+ * pwwn: Port WWN
+ * nwwn: Nodw WWN
+ * promiscous: to enable promisc mode for mac interface
+ */
+FCOE_STATUS FCOE_CreatePort(
+ const FCOE_UINT8 *macLinkName, /* maximum len: 32 */
+ FCOE_UINT8 portType,
+ FCOE_PORT_WWN pwwn,
+ FCOE_PORT_WWN nwwn,
+ FCOE_UINT8 promiscusous
+);
+
+FCOE_STATUS FCOE_DeletePort(
+ const FCOE_UINT8 *macLinkName
+);
+
+/*
+ * Make sure to free the memory pointed by portlist
+ */
+FCOE_STATUS FCOE_GetPortList(
+ FCOE_UINT32 *port_num,
+ FCOE_PORT_ATTRIBUTE **portlist
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFCOE_H */
diff --git a/usr/src/lib/libfcoe/common/llib-lfcoe b/usr/src/lib/libfcoe/common/llib-lfcoe
new file mode 100644
index 0000000000..888c17113e
--- /dev/null
+++ b/usr/src/lib/libfcoe/common/llib-lfcoe
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfcoe.h>
diff --git a/usr/src/lib/libfcoe/common/mapfile-vers b/usr/src/lib/libfcoe/common/mapfile-vers
new file mode 100644
index 0000000000..ba73d9e4dd
--- /dev/null
+++ b/usr/src/lib/libfcoe/common/mapfile-vers
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate {
+ global:
+ FCOE_CreatePort;
+ FCOE_DeletePort;
+ FCOE_GetPortList;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/libfcoe/i386/Makefile b/usr/src/lib/libfcoe/i386/Makefile
new file mode 100644
index 0000000000..433a471ad6
--- /dev/null
+++ b/usr/src/lib/libfcoe/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# 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
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libfcoe/sparc/Makefile b/usr/src/lib/libfcoe/sparc/Makefile
new file mode 100644
index 0000000000..948a3578b3
--- /dev/null
+++ b/usr/src/lib/libfcoe/sparc/Makefile
@@ -0,0 +1,29 @@
+#
+# 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
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libfcoe/sparcv9/Makefile b/usr/src/lib/libfcoe/sparcv9/Makefile
new file mode 100644
index 0000000000..3f8aa611ca
--- /dev/null
+++ b/usr/src/lib/libfcoe/sparcv9/Makefile
@@ -0,0 +1,34 @@
+#
+# 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
+include ../../Makefile.lib.64
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile
index 1711bdda5c..f882753640 100644
--- a/usr/src/pkgdefs/Makefile
+++ b/usr/src/pkgdefs/Makefile
@@ -242,6 +242,9 @@ COMMON_SUBDIRS= \
SUNWfcprtr \
SUNWfcsm \
SUNWfctl \
+ SUNWfcoe \
+ SUNWfcoeu \
+ SUNWfcoet \
SUNWfilebench \
SUNWfmd \
SUNWfmdr \
diff --git a/usr/src/pkgdefs/SUNWfcoe/Makefile b/usr/src/pkgdefs/SUNWfcoe/Makefile
new file mode 100644
index 0000000000..0c86629d67
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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/SUNWfcoe/depend b/usr/src/pkgdefs/SUNWfcoe/depend
new file mode 100644
index 0000000000..31be17a927
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/depend
@@ -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 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
diff --git a/usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoe/pkginfo.tmpl
new file mode 100644
index 0000000000..c4a84e2dfa
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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="SUNWfcoe"
+NAME="Sun FCoE Transport Driver"
+ARCH="ISA"
+CATEGORY="system"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="root"
+CLASSES="none"
+DESC="Sun FCoE (Fibre Channel over Ethernet) Transport 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/SUNWfcoe/postinstall b/usr/src/pkgdefs/SUNWfcoe/postinstall
new file mode 100644
index 0000000000..4b9d341eed
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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=fcoe
+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/SUNWfcoe/preremove b/usr/src/pkgdefs/SUNWfcoe/preremove
new file mode 100644
index 0000000000..d7ef233dc6
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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=fcoe
+
+# Remove the driver entries but leave it attached.
+/usr/sbin/rem_drv -b ${BASEDIR} ${DRVR_NAME}
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWfcoe/prototype_com b/usr/src/pkgdefs/SUNWfcoe/prototype_com
new file mode 100644
index 0000000000..497cf4a41d
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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/SUNWfcoe/prototype_i386 b/usr/src/pkgdefs/SUNWfcoe/prototype_i386
new file mode 100644
index 0000000000..d551918064
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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
+#
+#
+# SUNWfcoe
+#
+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/fcoe.conf 0644 root sys
+f none kernel/drv/fcoe 0755 root sys
+f none kernel/drv/amd64/fcoe 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWfcoe/prototype_sparc b/usr/src/pkgdefs/SUNWfcoe/prototype_sparc
new file mode 100644
index 0000000000..6c8079b01a
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoe/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
+#
+#
+# SUNWfcoe
+#
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/fcoe.conf 0644 root sys
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/fcoe 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWfcoet/Makefile b/usr/src/pkgdefs/SUNWfcoet/Makefile
new file mode 100644
index 0000000000..0c86629d67
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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/SUNWfcoet/depend b/usr/src/pkgdefs/SUNWfcoet/depend
new file mode 100644
index 0000000000..d7fda4ce50
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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 SUNWstmf Sun Common Multiprotocol SCSI Target
diff --git a/usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoet/pkginfo.tmpl
new file mode 100644
index 0000000000..422a84b86c
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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="SUNWfcoet"
+NAME="Sun FCoE COMSTAR Driver"
+ARCH="ISA"
+CATEGORY="system"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="root"
+CLASSES="none"
+DESC="Sun FCoE (Fibre Channel over Ethernet) COMSTAR 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/SUNWfcoet/postinstall b/usr/src/pkgdefs/SUNWfcoet/postinstall
new file mode 100644
index 0000000000..ef6442a273
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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=fcoet
+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/SUNWfcoet/preremove b/usr/src/pkgdefs/SUNWfcoet/preremove
new file mode 100644
index 0000000000..59e1ab1fff
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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=fcoet
+
+# Remove the driver entries but leave it attached.
+/usr/sbin/rem_drv -b ${BASEDIR} ${DRVR_NAME}
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWfcoet/prototype_com b/usr/src/pkgdefs/SUNWfcoet/prototype_com
new file mode 100644
index 0000000000..497cf4a41d
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/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/SUNWfcoet/prototype_i386 b/usr/src/pkgdefs/SUNWfcoet/prototype_i386
new file mode 100644
index 0000000000..26213fc6ce
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/prototype_i386
@@ -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 Intel specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWfcoet
+#
+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/fcoet 0755 root sys
+f none kernel/drv/amd64/fcoet 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWfcoet/prototype_sparc b/usr/src/pkgdefs/SUNWfcoet/prototype_sparc
new file mode 100644
index 0000000000..dba42598c9
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoet/prototype_sparc
@@ -0,0 +1,51 @@
+#
+# 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
+#
+#
+# SUNWfcoet
+#
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/fcoet 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWfcoeu/Makefile b/usr/src/pkgdefs/SUNWfcoeu/Makefile
new file mode 100644
index 0000000000..5f3bd3a917
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/Makefile
@@ -0,0 +1,34 @@
+#
+# 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
+
+install: all pkg
+
+include ../Makefile.targ
diff --git a/usr/src/pkgdefs/SUNWfcoeu/depend b/usr/src/pkgdefs/SUNWfcoeu/depend
new file mode 100644
index 0000000000..f81330f9a8
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/depend
@@ -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 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
diff --git a/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl
new file mode 100644
index 0000000000..ea21cdce9f
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/pkginfo.tmpl
@@ -0,0 +1,48 @@
+#
+# 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="SUNWfcoeu"
+NAME="Sun FCoE Port Management Library"
+ARCH="ISA"
+CATEGORY="system"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="usr"
+CLASSES="none"
+DESC="Sun FCoE (Fibre Channel over Ethernet) Port Management Library"
+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="false"
+SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_com b/usr/src/pkgdefs/SUNWfcoeu/prototype_com
new file mode 100644
index 0000000000..345a0cbb0b
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_com
@@ -0,0 +1,45 @@
+#
+# 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
+d none usr 755 root sys
+d none usr/lib 755 root bin
+f none usr/lib/libfcoe.so.1 755 root bin
+s none usr/lib/libfcoe.so=libfcoe.so.1
+f none usr/lib/llib-lfcoe 644 root bin
+f none usr/lib/llib-lfcoe.ln 644 root bin
+d none usr/include 755 root bin
+f none usr/include/libfcoe.h 644 root bin
diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_i386 b/usr/src/pkgdefs/SUNWfcoeu/prototype_i386
new file mode 100644
index 0000000000..1ce5151e29
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_i386
@@ -0,0 +1,48 @@
+#
+# 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
+#
+d none usr/lib/amd64 0755 root bin
+f none usr/lib/amd64/libfcoe.so.1 0755 root bin
+s none usr/lib/amd64/libfcoe.so=libfcoe.so.1
+f none usr/lib/amd64/llib-lfcoe.ln 644 root bin
diff --git a/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc b/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc
new file mode 100644
index 0000000000..ee12ab97c1
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoeu/prototype_sparc
@@ -0,0 +1,47 @@
+#
+# 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
+#
+d none usr/lib/sparcv9 0755 root bin
+f none usr/lib/sparcv9/libfcoe.so.1 0755 root bin
+s none usr/lib/sparcv9/libfcoe.so=libfcoe.so.1
+f none usr/lib/sparcv9/llib-lfcoe.ln 644 root bin
diff --git a/usr/src/pkgdefs/SUNWfcprt/depend b/usr/src/pkgdefs/SUNWfcprt/depend
index 4b530fcac6..51027a794f 100644
--- a/usr/src/pkgdefs/SUNWfcprt/depend
+++ b/usr/src/pkgdefs/SUNWfcprt/depend
@@ -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.
#
#
@@ -50,4 +50,5 @@ P SUNWcsu Core Solaris, (Usr)
P SUNWcsd Core Solaris Devices
P SUNWcsl Core Solaris Libraries
P SUNWcfcl Common Fibre Channel HBA API Library (Usr)
+P SUNWfcoeu SUN FCoE Port Management Library
diff --git a/usr/src/pkgdefs/SUNWfcprtr/preremove b/usr/src/pkgdefs/SUNWfcprtr/preremove
index 140041498f..ab22a73816 100644
--- a/usr/src/pkgdefs/SUNWfcprtr/preremove
+++ b/usr/src/pkgdefs/SUNWfcprtr/preremove
@@ -20,7 +20,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.
#
#
@@ -57,4 +57,25 @@ if [ "${SVCPROP}" = "true" ]; then
fi
svcadm refresh ${SERVICE}
fi
+
+SERVICE="svc:/network/fcoe_config:default"
+
+#
+# Confirm service is installed, otherwise exit.
+#
+/usr/bin/svcprop -q ${SERVICE} || exit 0
+
+SVCPROP=`svcprop -p general/enabled ${SERVICE}`
+
+#
+# Check to see if the service is running and if so disable it.
+#
+if [ "${SVCPROP}" = "true" ]; then
+ svcadm disable ${SERVICE}
+ if [ $? -ne 0 ]; then
+ echo "\n$0 Disabling of ${SERVICE} failed!\n" >&2
+ exit 1
+ fi
+ svcadm refresh ${SERVICE}
+fi
exit 0
diff --git a/usr/src/pkgdefs/SUNWfcprtr/prototype_com b/usr/src/pkgdefs/SUNWfcprtr/prototype_com
index 5a82fd393f..580312340a 100644
--- a/usr/src/pkgdefs/SUNWfcprtr/prototype_com
+++ b/usr/src/pkgdefs/SUNWfcprtr/prototype_com
@@ -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.
#
#
@@ -45,7 +45,9 @@ d none var/svc 755 root sys
d none var/svc/manifest 755 root sys
d none var/svc/manifest/network 0755 root sys
f manifest var/svc/manifest/network/npiv_config.xml 0444 root sys
+f manifest var/svc/manifest/network/fcoe_config.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/fcoeconfig 0555 root bin
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index debf200d36..4becf60fae 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -305,6 +305,7 @@ superfluous_nonglobal_zone_files="
lib/svc/method/fc-fabric
lib/svc/method/iscsid
lib/svc/method/npivconfig
+ lib/svc/method/fcoeconfig
lib/svc/method/sf880dr
lib/svc/method/svc-cvcd
lib/svc/method/svc-dcs
@@ -362,6 +363,7 @@ superfluous_nonglobal_zone_files="
var/log/pool
var/svc/manifest/network/iscsi_initiator.xml
var/svc/manifest/network/npiv_config.xml
+ var/svc/manifest/network/fcoe_config.xml
var/svc/manifest/network/rpc/mdcomm.xml
var/svc/manifest/network/rpc/meta.xml
var/svc/manifest/network/rpc/metamed.xml
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index f97b615a4d..e6a73bd8aa 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -840,6 +840,10 @@ FCT_OBJS += discovery.o fct.o
QLT_OBJS += 2400.o 2500.o qlt.o qlt_dma.o
+FCOE_OBJS += fcoe.o fcoe_eth.o fcoe_fc.o
+
+FCOET_OBJS += fcoet.o fcoet_eth.o fcoet_fc.o
+
ISCSIT_SHARED_OBJS += \
iscsit_common.o
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 1832617643..46f2e67e5d 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -576,6 +576,11 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/comstar/port/qlt/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/comstar/port/fcoet/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
+
$(OBJS_DIR)/%.o: $(COMMONBASE)/iscsit/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -604,6 +609,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/drm/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
+$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/fcoe/%.c
+ $(COMPILE.c) -o $@ $<
+ $(CTFCONVERT_O)
+
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
@@ -1671,6 +1680,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/qlt/%.c
$(LINTS_DIR)/%.ln: $(COMMONBASE)/iscsit/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/fcoet/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/comstar/port/iscsit/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
@@ -1689,6 +1701,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/dmfe/%.c
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/drm/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
+$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/fcoe/%.c
+ @($(LHEAD) $(LINT.c) $< $(LTAIL))
+
$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/hotplug/hpcsvc/%.c
@($(LHEAD) $(LINT.c) $< $(LTAIL))
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
index 022fa217f7..462fdc8c52 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
@@ -83,7 +83,7 @@ sbd_do_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd,
if (iolen == 0)
break;
if (sst->sst_data_read(sst, laddr, (uint64_t)iolen,
- dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
+ dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
/* Do not need to do xfer anymore, just complete it */
dbuf->db_data_size = 0;
@@ -146,6 +146,27 @@ sbd_handle_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
stmf_scsilib_send_status(task, STATUS_GOOD, 0);
return;
}
+ if (dbuf->db_flags & DB_DONT_REUSE) {
+ /* allocate new dbuf */
+ uint32_t maxsize, minsize, old_minsize;
+ stmf_free_dbuf(task, dbuf);
+
+ maxsize = (scmd->len > (128*1024)) ? 128*1024 : scmd->len;
+ minsize = maxsize >> 2;
+ do {
+ old_minsize = minsize;
+ dbuf = stmf_alloc_dbuf(task, maxsize, &minsize, 0);
+ } while ((dbuf == NULL) && (old_minsize > minsize) &&
+ (minsize >= 512));
+ if (dbuf == NULL) {
+ scmd->nbufs --;
+ if (scmd->nbufs == 0) {
+ stmf_abort(STMF_QUEUE_TASK_ABORT, task,
+ STMF_ALLOC_FAILURE, NULL);
+ }
+ return;
+ }
+ }
sbd_do_read_xfer(task, scmd, dbuf);
}
@@ -329,7 +350,7 @@ sbd_handle_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
if (iolen == 0)
break;
if (sst->sst_data_write(sst, laddr, (uint64_t)iolen,
- dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
+ dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
break;
}
@@ -351,7 +372,7 @@ WRITE_XFER_DONE:
stmf_scsilib_send_status(task, STATUS_GOOD, 0);
return;
}
- if (dbuf_reusable == 0) {
+ if (dbuf->db_flags & DB_DONT_REUSE || dbuf_reusable == 0) {
uint32_t maxsize, minsize, old_minsize;
/* free current dbuf and allocate a new one */
stmf_free_dbuf(task, dbuf);
@@ -746,9 +767,9 @@ void
sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
uint8_t *p, int bsize)
{
- uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
- uint32_t cmd_size;
- uint8_t page_length;
+ uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
+ uint32_t cmd_size;
+ uint8_t page_length;
/*
* Basic protocol checks.
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c
new file mode 100644
index 0000000000..2a22709bb6
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c
@@ -0,0 +1,1035 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 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/modhash.h>
+#include <sys/scsi/scsi.h>
+#include <sys/ethernet.h>
+
+/*
+ * COMSTAR header files
+ */
+#include <sys/stmf_defines.h>
+#include <sys/fct_defines.h>
+#include <sys/stmf.h>
+#include <sys/portif.h>
+#include <sys/fct.h>
+
+/*
+ * FCoE header files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoet.h>
+#include <fcoet_eth.h>
+#include <fcoet_fc.h>
+
+/*
+ * static function forward declaration
+ */
+static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp);
+static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp);
+static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+ cred_t *credp, int *rval);
+static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss);
+static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss);
+static void fcoet_watchdog(void *arg);
+static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss);
+static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port,
+ uint32_t size, uint32_t *pminsize, uint32_t flags);
+static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
+static int fcoet_dbuf_init(fcoet_soft_state_t *ss);
+static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss);
+static uint_t
+fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
+static uint_t
+fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
+
+/*
+ * Driver identificaton stuff
+ */
+static struct cb_ops fcoet_cb_ops = {
+ fcoet_open,
+ fcoet_close,
+ nodev,
+ nodev,
+ nodev,
+ nodev,
+ nodev,
+ fcoet_ioctl,
+ nodev,
+ nodev,
+ nodev,
+ nochpoll,
+ ddi_prop_op,
+ 0,
+ D_MP | D_NEW
+};
+
+static struct dev_ops fcoet_ops = {
+ DEVO_REV,
+ 0,
+ nodev,
+ nulldev,
+ nulldev,
+ fcoet_attach,
+ fcoet_detach,
+ nodev,
+ &fcoet_cb_ops,
+ NULL,
+ ddi_power
+};
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ FCOET_MOD_NAME,
+ &fcoet_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, &modldrv, NULL
+};
+
+/*
+ * Driver's global variables
+ */
+static kmutex_t fcoet_mutex;
+static void *fcoet_state = NULL;
+
+int fcoet_use_ext_log = 1;
+static char fcoet_provider_name[] = "fcoet";
+static struct stmf_port_provider *fcoet_pp = NULL;
+
+/*
+ * Common loadable module entry points _init, _fini, _info
+ */
+
+int
+_init(void)
+{
+ int ret;
+
+ ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0);
+ if (ret == 0) {
+ fcoet_pp = (stmf_port_provider_t *)
+ stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
+ fcoet_pp->pp_portif_rev = PORTIF_REV_1;
+ fcoet_pp->pp_name = fcoet_provider_name;
+ if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) {
+ stmf_free(fcoet_pp);
+ ddi_soft_state_fini(&fcoet_state);
+ return (EIO);
+ }
+
+ mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0);
+ ret = mod_install(&modlinkage);
+ if (ret) {
+ stmf_deregister_port_provider(fcoet_pp);
+ stmf_free(fcoet_pp);
+ mutex_destroy(&fcoet_mutex);
+ ddi_soft_state_fini(&fcoet_state);
+ }
+ }
+
+ FCOET_LOG("_init", "exit _init with %x", ret);
+ return (ret);
+}
+
+int
+_fini(void)
+{
+ int ret;
+
+ ret = mod_remove(&modlinkage);
+ if (ret == 0) {
+ stmf_deregister_port_provider(fcoet_pp);
+ stmf_free(fcoet_pp);
+ mutex_destroy(&fcoet_mutex);
+ ddi_soft_state_fini(&fcoet_state);
+ }
+
+ FCOET_LOG("_fini", "exit _fini with %x", ret);
+ return (ret);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * Autoconfiguration entry points: attach, detach, getinfo
+ */
+
+static int
+fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int ret = DDI_FAILURE;
+ int instance;
+ fcoet_soft_state_t *ss;
+
+ instance = ddi_get_instance(dip);
+ FCOET_LOG("fcoet_attach", "get instance %d", instance);
+
+ switch (cmd) {
+ case DDI_ATTACH:
+ ret = ddi_soft_state_zalloc(fcoet_state, instance);
+ if (ret != DDI_SUCCESS) {
+ return (ret);
+ }
+
+ ss = ddi_get_soft_state(fcoet_state, instance);
+ ss->ss_instance = instance;
+ ss->ss_dip = dip;
+
+ ret = fcoet_attach_init(ss);
+ if (ret != FCOE_SUCCESS) {
+ ddi_soft_state_free(fcoet_state, instance);
+ ret = DDI_FAILURE;
+ }
+
+ FCOET_LOG("fcoet_attach", "end with-%x", ret);
+ break;
+
+ case DDI_RESUME:
+ ret = DDI_SUCCESS;
+ break;
+
+ default:
+ FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd);
+ break;
+ }
+
+ return (ret);
+}
+
+static int
+fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ int ret = DDI_FAILURE;
+ int fcoe_ret;
+ int instance;
+ fcoet_soft_state_t *ss;
+
+ instance = ddi_get_instance(dip);
+ ss = ddi_get_soft_state(fcoet_state, instance);
+ if (ss == NULL) {
+ return (ret);
+ }
+
+ switch (cmd) {
+ case DDI_DETACH:
+ fcoe_ret = fcoet_detach_uninit(ss);
+ if (fcoe_ret == FCOE_SUCCESS) {
+ ret = DDI_SUCCESS;
+ }
+
+ FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x",
+ fcoe_ret);
+ break;
+
+ case DDI_SUSPEND:
+ ret = DDI_SUCCESS;
+ break;
+
+ default:
+ FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd);
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * Device access entry points
+ */
+static int
+fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp)
+{
+ int instance;
+ fcoet_soft_state_t *ss;
+
+ if (otype != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ /*
+ * Since this is for debugging only, only allow root to issue ioctl now
+ */
+ if (drv_priv(credp)) {
+ return (EPERM);
+ }
+
+ instance = (int)getminor(*devp);
+ ss = ddi_get_soft_state(fcoet_state, instance);
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) {
+ /*
+ * It is already open for exclusive access.
+ * So shut the door on this caller.
+ */
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (EBUSY);
+ }
+
+ if (flag & FEXCL) {
+ if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) {
+ /*
+ * Exclusive operation not possible
+ * as it is already opened
+ */
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (EBUSY);
+ }
+ ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL;
+ }
+ ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN;
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+fcoet_close(dev_t dev, int flag, int otype, cred_t *credp)
+{
+ int instance;
+ fcoet_soft_state_t *ss;
+
+ if (otype != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ instance = (int)getminor(dev);
+ ss = ddi_get_soft_state(fcoet_state, instance);
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (ENODEV);
+ }
+
+ /*
+ * It looks there's one hole here, maybe there could several concurrent
+ * shareed open session, but we never check this case.
+ * But it will not hurt too much, disregard it now.
+ */
+ ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK;
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+ cred_t *credp, int *rval)
+{
+ fcoet_soft_state_t *ss;
+ int ret = 0;
+
+ if (drv_priv(credp) != 0) {
+ return (EPERM);
+ }
+
+ ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev));
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ switch (cmd) {
+ default:
+ FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd);
+ ret = ENOTTY;
+ break;
+ }
+
+ *rval = ret;
+ return (ret);
+}
+
+static fct_status_t
+fcoet_attach_init(fcoet_soft_state_t *ss)
+{
+ fcoe_client_t client_fcoet;
+ fcoe_port_t *eport;
+ fct_local_port_t *port;
+ fct_dbuf_store_t *fds;
+ char *mac_name;
+ char taskq_name[32];
+ int ret;
+
+ /*
+ * FCoE (fcoe is fcoet's dependent driver)
+ * First we need register fcoet to FCoE as one client
+ */
+ client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE |
+ EPORT_FLAG_IS_DIRECT_P2P;
+ client_fcoet.ect_max_fc_frame_size = 2136;
+ client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t);
+ client_fcoet.ect_rx_frame = fcoet_rx_frame;
+ 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;
+ ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, ss->ss_dip,
+ DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_name", &mac_name);
+ if (ret != DDI_PROP_SUCCESS) {
+ FCOET_LOG("fcoet_attach_init", "lookup_string failed");
+ return (DDI_FAILURE);
+ } else {
+ bcopy(mac_name, client_fcoet.ect_channel_name,
+ strlen(mac_name));
+ client_fcoet.ect_channel_name[strlen(mac_name)] = 0;
+ ddi_prop_free(mac_name);
+ }
+ FCOET_LOG("fcoet_attach_init", "channel_name is %s",
+ client_fcoet.ect_channel_name);
+
+ /*
+ * It's FCoE's responsiblity to initialize eport's all elements
+ */
+ eport = fcoe_register_client(&client_fcoet);
+ if (eport == NULL) {
+ goto fail_register_client;
+ }
+
+ /*
+ * Now it's time to register local port to FCT
+ */
+ if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) {
+ goto fail_init_dbuf;
+ }
+
+ fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
+ if (fds == NULL) {
+ goto fail_alloc_dbuf;
+ } else {
+ fds->fds_alloc_data_buf = fcoet_dbuf_alloc;
+ fds->fds_free_data_buf = fcoet_dbuf_free;
+ fds->fds_fca_private = (void *)ss;
+ }
+
+ port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
+ if (port == NULL) {
+ goto fail_alloc_port;
+ } else {
+ /*
+ * Do ss's initialization now
+ */
+ (void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d",
+ ss->ss_instance);
+ ret = ddi_create_minor_node(ss->ss_dip, "admin",
+ S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0);
+ if (ret != DDI_SUCCESS) {
+ goto fail_minor_node;
+ }
+
+ ss->ss_state = FCT_STATE_OFFLINE;
+ ss->ss_state_not_acked = 1;
+ ss->ss_flags = 0;
+ ss->ss_port = port;
+ ss->ss_eport = eport;
+ FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
+
+ ss->ss_rportid_in_dereg = 0;
+ ss->ss_rport_dereg_state = 0;
+
+ ss->ss_next_sol_oxid = 0xFFFF;
+ ss->ss_next_unsol_rxid = 0xFFFF;
+ ss->ss_sol_oxid_hash = mod_hash_create_idhash(
+ "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE,
+ mod_hash_null_valdtor);
+ ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
+ "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE,
+ mod_hash_null_valdtor);
+
+ ss->ss_watch_count = 0;
+ mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
+ cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
+
+ list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t),
+ offsetof(fcoet_exchange_t, xch_abort_node));
+
+ ss->ss_sol_flogi = NULL;
+ ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
+
+ bzero(&ss->ss_link_info, sizeof (fct_link_info_t));
+
+ ss->ss_ioctl_flags = 0;
+ mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
+
+ ss->ss_change_state_flags = 0;
+ }
+
+ /*
+ * Do port's initialization
+ *
+ * port_fct_private and port_lport have been initialized by fct_alloc
+ */
+ port->port_fca_private = ss;
+ bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8);
+ bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8);
+ port->port_default_alias = ss->ss_alias;
+ port->port_sym_node_name = NULL;
+ port->port_sym_port_name = NULL;
+
+ port->port_pp = fcoet_pp;
+
+ port->port_hard_address = 0;
+ port->port_max_logins = FCOET_MAX_LOGINS;
+ port->port_max_xchges = FCOET_MAX_XCHGES;
+ port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t);
+ port->port_fca_rp_private_size = 0;
+ port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t);
+ port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t);
+
+ port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */
+ port->port_fds = fds;
+
+ port->port_get_link_info = fcoet_get_link_info;
+ port->port_register_remote_port = fcoet_register_remote_port;
+ port->port_deregister_remote_port = fcoet_deregister_remote_port;
+ port->port_send_cmd = fcoet_send_cmd;
+ port->port_xfer_scsi_data = fcoet_xfer_scsi_data;
+ port->port_send_cmd_response = fcoet_send_cmd_response;
+ port->port_abort_cmd = fcoet_abort_cmd;
+ port->port_ctl = fcoet_ctl;
+ port->port_flogi_xchg = fcoet_do_flogi;
+ port->port_populate_hba_details = fcoet_populate_hba_fru_details;
+ if (fct_register_local_port(port) != FCT_SUCCESS) {
+ goto fail_register_port;
+ }
+
+ /*
+ * Start watchdog thread
+ */
+ (void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq",
+ ss->ss_instance);
+ taskq_name[31] = 0;
+ if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
+ taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
+ goto fail_create_taskq;
+ }
+
+ atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG);
+ (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
+ fcoet_watchdog, ss, DDI_SLEEP);
+ while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
+ delay(10);
+ }
+
+ ddi_report_dev(ss->ss_dip);
+ return (DDI_SUCCESS);
+
+fail_create_taskq:
+ if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
+ cv_broadcast(&ss->ss_watch_cv);
+ while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ delay(10);
+ }
+ }
+
+ ddi_taskq_destroy(ss->ss_watchdog_taskq);
+ FCOET_LOG("fcoet_attach_init", "fail_register_port");
+
+fail_register_port:
+ mutex_destroy(&ss->ss_ioctl_mutex);
+ mutex_destroy(&ss->ss_watch_mutex);
+ cv_destroy(&ss->ss_watch_cv);
+ mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
+ mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
+ list_destroy(&ss->ss_abort_xchg_list);
+ FCOET_LOG("fcoet_attach_init", "fail_create_taskq");
+
+fail_minor_node:
+ fct_free(port);
+ FCOET_LOG("fcoet_attach_init", "fail_minor_node");
+
+fail_alloc_port:
+ fct_free(fds);
+ FCOET_LOG("fcoet_attach_init", "fail_alloc_port");
+
+fail_alloc_dbuf:
+ fcoet_dbuf_destroy(ss);
+ FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf");
+
+fail_init_dbuf:
+ ss->ss_eport->eport_deregister_client(ss->ss_eport);
+ FCOET_LOG("fcoet_attach_init", "fail_init_dbuf");
+
+fail_register_client:
+ FCOET_LOG("fcoet_attach_init", "fail_register_client");
+ return (DDI_FAILURE);
+}
+
+static fct_status_t
+fcoet_detach_uninit(fcoet_soft_state_t *ss)
+{
+ if ((ss->ss_state != FCT_STATE_OFFLINE) ||
+ ss->ss_state_not_acked) {
+ return (FCOE_FAILURE);
+ }
+
+ /*
+ * Avoid modunload before running fcinfo remove-target-port
+ */
+ if (ss->ss_eport != NULL &&
+ ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) {
+ return (FCOE_FAILURE);
+ }
+
+ if (ss->ss_port == NULL) {
+ return (FCOE_SUCCESS);
+ }
+
+ ss->ss_sol_oxid_hash_empty = 1;
+ ss->ss_unsol_rxid_hash_empty = 1;
+ mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss);
+ mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss);
+ if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) {
+ return (FCOE_FAILURE);
+ }
+
+ /*
+ * We need offline the port manually, before we want to detach it
+ * or it will not succeed.
+ */
+ if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) {
+ FCOET_LOG("fcoet_detach_uninit",
+ "fct_deregister_local_port failed");
+ return (FCOE_FAILURE);
+ }
+
+ /*
+ * Stop watchdog
+ */
+ if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
+ cv_broadcast(&ss->ss_watch_cv);
+ while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ delay(10);
+ }
+ }
+
+ ddi_taskq_destroy(ss->ss_watchdog_taskq);
+
+ /*
+ * Release all resources
+ */
+ mutex_destroy(&ss->ss_ioctl_mutex);
+ mutex_destroy(&ss->ss_watch_mutex);
+ cv_destroy(&ss->ss_watch_cv);
+ mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
+ mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
+ list_destroy(&ss->ss_abort_xchg_list);
+
+ fct_free(ss->ss_port->port_fds);
+ fct_free(ss->ss_port);
+ ss->ss_port = NULL;
+
+ fcoet_dbuf_destroy(ss);
+
+ if (ss->ss_eport != NULL &&
+ ss->ss_eport->eport_deregister_client != NULL) {
+ ss->ss_eport->eport_deregister_client(ss->ss_eport);
+ }
+ ddi_soft_state_free(fcoet_state, ss->ss_instance);
+ return (FCOE_SUCCESS);
+}
+
+static void
+fcoet_watchdog(void *arg)
+{
+ fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg;
+ clock_t tmp_delay = 0;
+ fcoet_exchange_t *xchg, *xchg_next;
+
+ FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss);
+
+ mutex_enter(&ss->ss_watch_mutex);
+ atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING);
+ tmp_delay = STMF_SEC2TICK(1)/2;
+
+ while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
+ ss->ss_watch_count++;
+
+ if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) {
+ fcoet_handle_sol_flogi(ss);
+ }
+ for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) {
+ xchg_next = list_next(&ss->ss_abort_xchg_list, xchg);
+ if (xchg->xch_ref == 0) {
+ list_remove(&ss->ss_abort_xchg_list, xchg);
+ mutex_exit(&ss->ss_watch_mutex);
+ /* xchg abort done */
+ if (xchg->xch_dbuf_num) {
+ kmem_free((void*)xchg->xch_dbufs,
+ xchg->xch_dbuf_num *
+ sizeof (void *));
+ xchg->xch_dbufs = NULL;
+ xchg->xch_dbuf_num = 0;
+ }
+ fct_cmd_fca_aborted(xchg->xch_cmd,
+ FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
+ mutex_enter(&ss->ss_watch_mutex);
+ }
+ xchg = xchg_next;
+ }
+
+ atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING);
+ (void) cv_timedwait(&ss->ss_watch_cv,
+ &ss->ss_watch_mutex, ddi_get_lbolt() +
+ (clock_t)tmp_delay);
+ atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING);
+ }
+
+ /*
+ * Ensure no ongoing FLOGI, before terminate the watchdog
+ */
+ if (ss->ss_sol_flogi) {
+ fcoet_clear_sol_exchange(ss->ss_sol_flogi);
+ fct_free(ss->ss_sol_flogi->xch_cmd);
+ ss->ss_sol_flogi = NULL;
+ }
+
+ atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING);
+ mutex_exit(&ss->ss_watch_mutex);
+}
+
+static void
+fcoet_handle_sol_flogi(fcoet_soft_state_t *ss)
+{
+ clock_t twosec = STMF_SEC2TICK(2);
+
+check_state_again:
+ if (ss->ss_flags & SS_FLAG_PORT_DISABLED) {
+ ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
+ }
+
+ switch (ss->ss_sol_flogi_state) {
+ case SFS_WAIT_LINKUP:
+ if (ss->ss_sol_flogi) {
+ if (ss->ss_sol_flogi->xch_ref == 0) {
+ fcoet_clear_sol_exchange(ss->ss_sol_flogi);
+ fct_free(ss->ss_sol_flogi->xch_cmd);
+ ss->ss_sol_flogi = NULL;
+ }
+ }
+ break;
+
+ case SFS_FLOGI_INIT:
+ if (ss->ss_sol_flogi) {
+ /*
+ * wait for the response to finish
+ */
+ ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI;
+ break;
+ }
+ fcoet_send_sol_flogi(ss);
+ ss->ss_sol_flogi_state++;
+ break;
+
+ case SFS_FLOGI_CHECK_TIMEOUT:
+ if ((ss->ss_sol_flogi->xch_start_time + twosec) <
+ ddi_get_lbolt()) {
+ ss->ss_sol_flogi_state++;
+ }
+ break;
+
+ case SFS_ABTS_INIT:
+ fcoet_send_sol_abts(ss->ss_sol_flogi);
+ ss->ss_sol_flogi_state++;
+ break;
+
+ case SFS_CLEAR_FLOGI:
+ if (ss->ss_sol_flogi) {
+ if (ss->ss_sol_flogi->xch_ref) {
+ break;
+ }
+ fcoet_clear_sol_exchange(ss->ss_sol_flogi);
+ fct_free(ss->ss_sol_flogi->xch_cmd);
+ ss->ss_sol_flogi = NULL;
+ }
+ ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
+ goto check_state_again;
+
+ case SFS_FLOGI_ACC:
+ ss->ss_sol_flogi_state++;
+ goto check_state_again;
+
+ case SFS_FLOGI_DONE:
+ if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) &&
+ ss->ss_sol_flogi) {
+ fcoet_clear_sol_exchange(ss->ss_sol_flogi);
+ fct_free(ss->ss_sol_flogi->xch_cmd);
+ ss->ss_sol_flogi = NULL;
+ }
+
+ /*
+ * We'd better to offline it first, and delay 0.1 seconds,
+ * before we say it's on again.
+ */
+ fct_handle_event(ss->ss_port,
+ FCT_EVENT_LINK_DOWN, 0, NULL);
+ delay(STMF_SEC2TICK(1)/10);
+ fct_handle_event(ss->ss_port,
+ FCT_EVENT_LINK_UP, 0, NULL);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+/* ARGSUSED */
+static int
+fcoet_dbuf_init(fcoet_soft_state_t *ss)
+{
+ return (FCOE_SUCCESS);
+}
+
+/* ARGSUSED */
+static void
+fcoet_dbuf_destroy(fcoet_soft_state_t *ss)
+{
+
+}
+
+/* ARGSUSED */
+static stmf_data_buf_t *
+fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
+ uint32_t flags)
+{
+ stmf_data_buf_t *dbuf;
+ int add_size;
+ int sge_num;
+ int sge_size;
+ int idx;
+ int ii;
+ void *netb;
+ uint8_t *fc_buf;
+ fcoet_soft_state_t *ss =
+ (fcoet_soft_state_t *)port->port_fca_private;
+
+ if (size > FCOET_MAX_DBUF_LEN) {
+ if (*pminsize > FCOET_MAX_DBUF_LEN) {
+ return (NULL);
+ }
+
+ size = FCOET_MAX_DBUF_LEN;
+ }
+
+ sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1;
+ add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) +
+ sge_num * sizeof (mblk_t *);
+ dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0);
+ if (dbuf == NULL) {
+ return (NULL);
+ }
+ dbuf->db_buf_size = size;
+ dbuf->db_data_size = size;
+ dbuf->db_sglist_length = 0;
+ dbuf->db_flags |= DB_DONT_REUSE;
+ FCOET_SET_SEG_NUM(dbuf, sge_num);
+
+ /*
+ * Initialize non-last sg entries
+ */
+ for (idx = 0; idx < sge_num - 1; idx++) {
+ sge_size = ss->ss_fcp_data_payload_size;
+ netb = ss->ss_eport->eport_alloc_netb(
+ ss->ss_eport, sizeof (fcoe_fc_frame_header_t) +
+ sge_size, &fc_buf);
+ if (netb == NULL) {
+ for (ii = 0; ii < idx; ii++) {
+ ss->ss_eport->eport_free_netb(
+ FCOET_GET_NETB(dbuf, ii));
+ }
+ stmf_free(dbuf);
+ FCOET_LOG("fcoe_dbuf_alloc", "no netb");
+ return (NULL);
+ }
+ FCOET_SET_NETB(dbuf, idx, netb);
+ dbuf->db_sglist[idx].seg_addr = fc_buf +
+ sizeof (fcoe_fc_frame_header_t);
+ dbuf->db_sglist[idx].seg_length = sge_size;
+ }
+
+ /*
+ * Initialize the last sg entry
+ */
+ if (size % ss->ss_fcp_data_payload_size) {
+ sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4);
+ } else {
+ sge_size = ss->ss_fcp_data_payload_size;
+ }
+
+ netb = ss->ss_eport->eport_alloc_netb(
+ ss->ss_eport,
+ sizeof (fcoe_fc_frame_header_t) +
+ sge_size, &fc_buf);
+ if (netb == NULL) {
+ for (ii = 0; ii < idx; ii++) {
+ ss->ss_eport->eport_free_netb(
+ FCOET_GET_NETB(dbuf, ii));
+ }
+ stmf_free(dbuf);
+ FCOET_LOG("fcoe_dbuf_alloc", "no netb");
+ return (NULL);
+ }
+
+ FCOET_SET_NETB(dbuf, idx, netb);
+ dbuf->db_sglist[idx].seg_addr = fc_buf +
+ sizeof (fcoe_fc_frame_header_t);
+ dbuf->db_sglist[idx].seg_length = sge_size;
+
+ /*
+ * Let COMSTAR know how many sg entries we will use
+ */
+ dbuf->db_sglist_length = idx + 1;
+
+ return (dbuf);
+}
+
+static void
+fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
+{
+ int idx;
+ fcoet_soft_state_t *ss =
+ (fcoet_soft_state_t *)fds->fds_fca_private;
+
+ for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) {
+ if (FCOET_GET_NETB(dbuf, idx)) {
+ ss->ss_eport->eport_free_netb(
+ FCOET_GET_NETB(dbuf, idx));
+ }
+ }
+
+ stmf_free(dbuf);
+}
+
+/*
+ * We should have initialized fcoe_frame_t before
+ */
+void
+fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch)
+{
+ FRM2TFM(frm)->tfm_fcoe_frame = frm;
+ FRM2TFM(frm)->tfm_xch = xch;
+ FRM2TFM(frm)->tfm_seq = NULL;
+}
+
+/* ARGSUSED */
+static uint_t
+fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+ fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg;
+
+ ss->ss_sol_oxid_hash_empty = 0;
+ FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val);
+ return (MH_WALK_CONTINUE);
+}
+
+/* ARGSUSED */
+static uint_t
+fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+ fcoet_soft_state_t *ss = (fcoet_soft_state_t *)arg;
+
+ ss->ss_sol_oxid_hash_empty = 0;
+ FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val);
+ return (MH_WALK_CONTINUE);
+}
+
+/* ARGSUSED */
+void
+fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val)
+{
+ ASSERT(val != NULL);
+ fcoet_exchange_t *xch = (fcoet_exchange_t *)val;
+ FCOET_BUSY_XCHG(xch);
+}
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h
new file mode 100644
index 0000000000..e2859d7f17
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h
@@ -0,0 +1,307 @@
+/*
+ * 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 _FCOET_H
+#define _FCOET_H
+
+#include <sys/stmf_defines.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+#define FCOET_VERSION "v20090311-1.00"
+#define FCOET_NAME "COMSTAR FCoET "
+#define FCOET_MOD_NAME FCOET_NAME FCOET_VERSION
+
+/*
+ * FCOET logging
+ */
+extern int fcoet_use_ext_log;
+
+/*
+ * Caution: 1) LOG will be available in debug/non-debug mode
+ * 2) Anything which can potentially flood the log should be under
+ * extended logging, and use FCOET_EXT_LOG.
+ * 3) Don't use FCOET_EXT_LOG in performance-critical code path, such
+ * as normal SCSI I/O code path. It could hurt system performance.
+ * 4) Use kmdb to change focet_use_ext_log in the fly to adjust
+ * tracing
+ */
+#define FCOET_EXT_LOG(log_ident, ...) \
+ { \
+ if (fcoet_use_ext_log) { \
+ fcoe_trace(log_ident, __VA_ARGS__); \
+ } \
+ }
+
+#define FCOET_LOG(log_ident, ...) \
+ fcoe_trace(log_ident, __VA_ARGS__)
+
+/*
+ * define common-used constants
+ */
+#define FCOET_MAX_LOGINS 2048
+#define FCOET_MAX_XCHGES 2048
+#define FCOET_SOL_HASH_SIZE 128
+#define FCOET_UNSOL_HASH_SIZE 2048
+
+typedef enum fcoet_sol_flogi_state {
+ SFS_WAIT_LINKUP = 0,
+ SFS_FLOGI_INIT,
+ SFS_FLOGI_CHECK_TIMEOUT,
+ SFS_ABTS_INIT,
+ SFS_CLEAR_FLOGI,
+ SFS_FLOGI_ACC,
+ SFS_FLOGI_DONE
+} fcoet_sol_flogi_state_t;
+
+/*
+ * define data structures
+ */
+struct fcoet_exchange;
+typedef struct fcoet_soft_state {
+ /*
+ * basic information
+ */
+ dev_info_t *ss_dip;
+ int ss_instance;
+ uint32_t ss_flags;
+ fct_local_port_t *ss_port;
+ fcoe_port_t *ss_eport;
+ char ss_alias[32];
+ uint32_t ss_fcp_data_payload_size;
+
+ /*
+ * support degregister remote port
+ */
+ uint32_t ss_rportid_in_dereg;
+ uint32_t ss_rport_dereg_state;
+
+ /*
+ * oxid/rxid
+ */
+ 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;
+ int ss_sol_oxid_hash_empty;
+ int ss_unsol_rxid_hash_empty;
+
+ /*
+ * watch thread related stuff
+ */
+ ddi_taskq_t *ss_watchdog_taskq;
+ kcondvar_t ss_watch_cv;
+ kmutex_t ss_watch_mutex;
+ uint64_t ss_watch_count;
+ list_t ss_abort_xchg_list;
+
+ /*
+ * topology discovery
+ */
+ struct fcoet_exchange *ss_sol_flogi;
+ fcoet_sol_flogi_state_t ss_sol_flogi_state;
+ fct_link_info_t ss_link_info;
+
+ /*
+ * ioctl related stuff
+ */
+ uint32_t ss_ioctl_flags;
+ kmutex_t ss_ioctl_mutex;
+
+ /*
+ * special stuff
+ */
+ uint32_t ss_change_state_flags;
+ uint8_t ss_state:7,
+ ss_state_not_acked:1;
+} fcoet_soft_state_t;
+
+#define SS_FLAG_UNSOL_FLOGI_DONE 0x0001
+#define SS_FLAG_REPORT_TO_FCT 0x0002
+#define SS_FLAG_PORT_DISABLED 0x0004
+#define SS_FLAG_STOP_WATCH 0x0008
+#define SS_FLAG_TERMINATE_WATCHDOG 0x0010
+#define SS_FLAG_WATCHDOG_RUNNING 0x0020
+#define SS_FLAG_DOG_WAITING 0x0040
+#define SS_FLAG_DELAY_PLOGI 0x0080
+
+/*
+ * Sequence and frame are transient objects, so their definition is simple.
+ */
+
+/*
+ * Sequence.
+ * we will not use sequence in current implementation
+ */
+typedef struct fcoet_sequence {
+ list_t seq_frame_list;
+ struct fcoet_exchange *seq_exchange;
+} fcoet_sequence_t;
+
+/*
+ * Frame
+ */
+typedef struct fcoet_frame {
+ list_node_t tfm_seq_node;
+ fcoe_frame_t *tfm_fcoe_frame;
+
+ struct fcoet_exchange *tfm_xch;
+ struct fcoet_sequence *tfm_seq;
+ uint8_t tfm_rctl;
+ uint8_t tfm_buf_idx;
+} fcoet_frame_t;
+
+/*
+ * FCOET_MAX_DBUF_LEN should better be consistent with sbd_scsi.c. Since
+ * sbd_scsi.c use 128k as the max dbuf size, we'd better define this between
+ * 32k - 128k.
+ */
+#define FCOET_MAX_DBUF_LEN 0x20000 /* 128 * 1024 */
+/*
+ * exchange - cmd alias
+ */
+typedef struct fcoet_exchange {
+ /*
+ * it is only used for ss_abort_xchg_list
+ */
+ list_node_t xch_abort_node;
+
+ /*
+ * We don't believe oxid/rxid in fct_cmd_t
+ */
+ uint16_t xch_oxid;
+ uint16_t xch_rxid;
+
+ uint32_t xch_flags;
+ fcoet_soft_state_t *xch_ss;
+ fct_cmd_t *xch_cmd;
+
+ fcoet_sequence_t *xch_current_seq;
+ clock_t xch_start_time;
+
+ stmf_data_buf_t **xch_dbufs;
+ uint8_t xch_dbuf_num;
+ uint8_t xch_sequence_no;
+ uint8_t xch_ref;
+
+ int xch_left_data_size;
+} fcoet_exchange_t;
+/*
+ * Add the reference to avoid such situation:
+ * 1, Frame received, then abort happen (maybe because local port offline, or
+ * remote port abort the cmd), cmd is aborted and then freed right after we
+ * get the exchange from hash table in fcoet_rx_frame.
+ * 2, Frame sent out, then queued in fcoe for release. then abort happen, cmd
+ * is aborted and then freed before fcoe_watchdog() call up to release the
+ * frame.
+ * These two situation should seldom happen. But just invoke this seems won't
+ * downgrade the performance too much, so we keep it.
+ */
+#define FCOET_BUSY_XCHG(xch) atomic_add_8(&(xch)->xch_ref, 1)
+#define FCOET_RELE_XCHG(xch) atomic_add_8(&(xch)->xch_ref, -1)
+
+#define XCH_FLAG_NONFCP_REQ_SENT 0x0001
+#define XCH_FLAG_NONFCP_RESP_SENT 0x0002
+#define XCH_FLAG_FCP_CMD_RCVD 0x0004
+#define XCH_FLAG_INI_ASKED_ABORT 0x0008
+#define XCH_FLAG_FCT_CALLED_ABORT 0x0010
+#define XCH_FLAG_IN_HASH_TABLE 0x0020
+
+/*
+ * IOCTL supporting stuff
+ */
+#define FCOET_IOCTL_FLAG_MASK 0xFF
+#define FCOET_IOCTL_FLAG_IDLE 0x00
+#define FCOET_IOCTL_FLAG_OPEN 0x01
+#define FCOET_IOCTL_FLAG_EXCL 0x02
+
+/*
+ * define common-used conversion and calculation macros
+ */
+#define FRM2SS(x_frm) \
+ ((fcoet_soft_state_t *)(x_frm)->frm_eport->eport_client_private)
+#define FRM2TFM(x_frm) ((fcoet_frame_t *)(x_frm)->frm_client_private)
+
+#define PORT2SS(x_port) ((fcoet_soft_state_t *)(x_port)->port_fca_private)
+#define EPORT2SS(x_port) ((fcoet_soft_state_t *)(x_port)->eport_client_private)
+
+#define XCH2ELS(x_xch) ((fct_els_t *)x_xch->xch_cmd->cmd_specific)
+#define XCH2CT(x_xch) ((fct_ct_t *)x_xch->xch_cmd->cmd_specific)
+#define XCH2TASK(x_xch) ((scsi_task_t *)x_xch->xch_cmd->cmd_specific)
+
+#define CMD2ELS(x_cmd) ((fct_els_t *)x_cmd->cmd_specific)
+#define CMD2CT(x_cmd) ((fct_sol_ct_t *)x_cmd->cmd_specific)
+#define CMD2TASK(x_cmd) ((scsi_task_t *)x_cmd->cmd_specific)
+#define CMD2XCH(x_cmd) ((fcoet_exchange_t *)x_cmd->cmd_fca_private)
+#define CMD2SS(x_cmd) \
+ ((fcoet_soft_state_t *)(x_cmd)->cmd_port->port_fca_private)
+
+void fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch);
+fct_status_t fcoet_send_status(fct_cmd_t *cmd);
+void fcoet_modhash_find_cb(mod_hash_key_t, mod_hash_val_t);
+
+/*
+ * DBUF stuff
+ */
+#define FCOET_DB_SEG_NUM(x_db) (x_db->db_port_private)
+#define FCOET_DB_NETB(x_db) \
+ (((uintptr_t)FCOET_DB_SEG_NUM(x_db)) * \
+ sizeof (struct stmf_sglist_ent) + (uintptr_t)(x_db)->db_sglist)
+
+#define FCOET_SET_SEG_NUM(x_db, x_num) \
+ { \
+ FCOET_DB_SEG_NUM(x_db) = (void *)(unsigned long)x_num; \
+ }
+
+#define FCOET_GET_SEG_NUM(x_db) ((int)(unsigned long)FCOET_DB_SEG_NUM(x_db))
+
+
+#define FCOET_SET_NETB(x_db, x_idx, x_netb) \
+ { \
+ ((void **)FCOET_DB_NETB(x_db))[x_idx] = x_netb; \
+ }
+
+#define FCOET_GET_NETB(x_db, x_idx) \
+ (((void **)FCOET_DB_NETB(x_db))[x_idx])
+
+#define PRT_FRM_HDR(x_p, x_f) \
+ { \
+ FCOET_LOG(x_p, "rctl/%x, type/%x, fctl/%x, oxid/%x", \
+ FCOE_B2V_1((x_f)->frm_hdr->hdr_r_ctl), \
+ FCOE_B2V_1((x_f)->frm_hdr->hdr_type), \
+ FCOE_B2V_3((x_f)->frm_hdr->hdr_f_ctl), \
+ FCOE_B2V_4((x_f)->frm_hdr->hdr_oxid)); \
+ }
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOET_H */
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
new file mode 100644
index 0000000000..99d5962ca2
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c
@@ -0,0 +1,1187 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * This file defines interfaces between fcoe and fcoet driver.
+ */
+
+/*
+ * 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/modhash.h>
+#include <sys/scsi/scsi.h>
+#include <sys/ethernet.h>
+
+/*
+ * COMSTAR header files
+ */
+#include <sys/stmf_defines.h>
+#include <sys/fct_defines.h>
+#include <sys/stmf.h>
+#include <sys/portif.h>
+#include <sys/fct.h>
+
+/*
+ * FCoE header files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoet.h>
+#include <fcoet_eth.h>
+
+/*
+ * function forward declaration
+ */
+static fcoet_exchange_t *fcoet_create_unsol_exchange(fcoe_frame_t *frame);
+static int fcoet_process_sol_fcp_data(fcoe_frame_t *frm);
+static int fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm);
+static int fcoet_process_unsol_els_req(fcoe_frame_t *frm);
+static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm);
+static int fcoet_process_unsol_abts_req(fcoe_frame_t *frame);
+static int fcoet_process_sol_abts_acc(fcoe_frame_t *frame);
+static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frame);
+static int fcoet_process_unsol_ct_req(fcoe_frame_t *frm);
+static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frame);
+static int fcoet_process_sol_flogi_rsp(fcoe_frame_t *frame);
+static int fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm);
+static int fcoet_send_fcp_status_done(fcoe_frame_t *frm);
+static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm);
+static int fcoet_send_sol_els_req_done(fcoe_frame_t *frm);
+static int fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm);
+static int fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm);
+static int fcoet_send_sol_bls_req_done(fcoe_frame_t *frm);
+static int fcoet_send_sol_ct_req_done(fcoe_frame_t *frm);
+static int fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch);
+
+/*
+ * rx_frame & release_sol_frame
+ * There should be no same OXID/RXID in on-going exchanges.
+ * RXID -> unsol_rxid_hash
+ * OXID -> sol_oxid_hash
+ */
+
+void
+fcoet_rx_frame(fcoe_frame_t *frm)
+{
+ uint8_t rctl = FRM_R_CTL(frm);
+
+ switch (rctl) {
+ case 0x01:
+ /*
+ * Solicited data
+ */
+ if (fcoet_process_sol_fcp_data(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_fcp_data failed");
+ }
+ break;
+
+ case 0x06:
+ /*
+ * Unsolicited fcp_cmnd
+ */
+ if (fcoet_process_unsol_fcp_cmd(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_unsol_fcp_cmd failed");
+ }
+ break;
+
+ case 0x22:
+ /*
+ * unsolicited ELS req
+ */
+ if (fcoet_process_unsol_els_req(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_unsol_els_req failed");
+ }
+ break;
+
+ case 0x23:
+ /*
+ * solicited ELS rsp
+ */
+ if (fcoet_process_sol_els_rsp(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_els_rsp failed");
+ }
+ break;
+
+ case 0x81:
+ /*
+ * unsolicted ABTS req
+ */
+ if (fcoet_process_unsol_abts_req(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_unsol_abts_req failed");
+ }
+ break;
+
+ case 0x84:
+ /*
+ * solicited ABTS acc response
+ */
+ if (fcoet_process_sol_abts_acc(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_abts_acc failed");
+ }
+ break;
+ case 0x85:
+ /*
+ * solcited ABTS rjt response
+ */
+ if (fcoet_process_sol_abts_rjt(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_abts_rjt failed");
+ }
+ break;
+
+ case 0x02:
+ /*
+ * unsolicited CT req
+ */
+ if (fcoet_process_unsol_ct_req(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_ct_rsp failed");
+ }
+ break;
+
+ case 0x03:
+ /*
+ * sol ct rsp
+ */
+ if (fcoet_process_sol_ct_rsp(frm)) {
+ FCOET_LOG("fcoet_rx_frame",
+ "fcoet_process_sol_ct_rsp failed");
+ }
+ break;
+
+ default:
+ /*
+ * Unsupported frame
+ */
+ PRT_FRM_HDR("Unsupported unsol frame: ", frm);
+ break;
+ }
+
+ /*
+ * Release the frame in the end
+ */
+ frm->frm_eport->eport_free_netb(frm->frm_netb);
+ frm->frm_eport->eport_release_frame(frm);
+}
+
+/*
+ * For solicited frames, after FCoE has sent it out, it will call this
+ * to notify client(FCoEI/FCoET) about its completion.
+ */
+void
+fcoet_release_sol_frame(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch;
+
+ /*
+ * From now, we should not access both frm_hdr and frm_payload. Its
+ * mblk could have been released by MAC driver.
+ */
+ switch (FRM2TFM(frm)->tfm_rctl) {
+ case 0x01:
+ if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ FCOET_RELE_XCHG(xch);
+ break;
+ }
+ if (fcoet_send_sol_fcp_data_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x05:
+ break;
+
+ case 0x07:
+ if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ FCOET_RELE_XCHG(xch);
+ break;
+ }
+
+ if (fcoet_send_fcp_status_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x23:
+ if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ FCOET_RELE_XCHG(xch);
+ break;
+ }
+ if (fcoet_send_unsol_els_rsp_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x22:
+ if (fcoet_send_sol_els_req_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x84:
+ if (fcoet_send_unsol_bls_acc_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x85:
+ if (fcoet_send_unsol_bls_rjt_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x81:
+ if (fcoet_send_sol_bls_req_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x02:
+ if (fcoet_send_sol_ct_req_done(frm)) {
+ ASSERT(0);
+ }
+ break;
+
+ case 0x03:
+ default:
+ /*
+ * Unsupported frame
+ */
+ PRT_FRM_HDR("Unsupported sol frame: ", frm);
+ break;
+ }
+
+ /*
+ * We should release the frame
+ */
+ FRM2SS(frm)->ss_eport->eport_release_frame(frm);
+}
+
+void
+fcoet_port_event(fcoe_port_t *eport, uint32_t event)
+{
+ fcoet_soft_state_t *ss = EPORT2SS(eport);
+ switch (event) {
+ case FCOE_NOTIFY_EPORT_LINK_UP:
+ if (eport->eport_mtu >= FCOE_MIN_MTU_SIZE) {
+ ss->ss_fcp_data_payload_size =
+ FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
+ } else {
+ ss->ss_fcp_data_payload_size =
+ FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
+ }
+ FCOET_LOG("fcoet_port_event", "LINK UP notified");
+ mutex_enter(&ss->ss_watch_mutex);
+ ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
+ cv_signal(&ss->ss_watch_cv);
+ mutex_exit(&ss->ss_watch_mutex);
+ break;
+ case FCOE_NOTIFY_EPORT_LINK_DOWN:
+ fct_handle_event(ss->ss_port,
+ FCT_EVENT_LINK_DOWN, 0, 0);
+ /* Need clear up all other things */
+ FCOET_LOG("fcoet_port_event", "LINK DOWN notified");
+ ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * For unsolicited exchanges, FCoET is only responsible for allocation of
+ * req_payload. FCT will allocate resp_payload after the exchange is
+ * passed on.
+ */
+static fcoet_exchange_t *
+fcoet_create_unsol_exchange(fcoe_frame_t *frm)
+{
+ uint8_t r_ctl;
+ int cdb_size;
+ fcoet_exchange_t *xch, *xch_tmp;
+ fct_cmd_t *cmd;
+ fcoe_fcp_cmnd_t *ffc;
+ uint32_t task_expected_len = 0;
+
+ r_ctl = FRM_R_CTL(frm);
+ switch (r_ctl) {
+ case 0x22:
+ /*
+ * FCoET's unsolicited ELS
+ */
+ cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
+ GET_STRUCT_SIZE(fcoet_exchange_t) +
+ frm->frm_payload_size, 0);
+ if (cmd == NULL) {
+ FCOET_EXT_LOG(0, "can't get cmd");
+ return (NULL);
+ }
+ break;
+
+ case 0x06:
+ /*
+ * FCoET's unsolicited SCSI cmd
+ */
+ cdb_size = 16; /* need improve later */
+ cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE,
+ FRM_S_ID(frm), frm->frm_payload, cdb_size,
+ STMF_TASK_EXT_NONE);
+ if (cmd == NULL) {
+ FCOET_EXT_LOG(0, "can't get fcp cmd");
+ return (NULL);
+ }
+ ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
+ task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl);
+ break;
+
+ default:
+ FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl);
+ return (NULL);
+ }
+
+ /*
+ * xch initialization
+ */
+ xch = CMD2XCH(cmd);
+ xch->xch_oxid = FRM_OXID(frm);
+ xch->xch_flags = 0;
+ xch->xch_ss = FRM2SS(frm);
+ xch->xch_cmd = cmd;
+ xch->xch_current_seq = NULL;
+ xch->xch_left_data_size = 0;
+ if (task_expected_len) {
+ xch->xch_dbuf_num =
+ (task_expected_len + FCOET_MAX_DBUF_LEN - 1) /
+ FCOET_MAX_DBUF_LEN;
+ xch->xch_dbufs =
+ kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *),
+ KM_SLEEP);
+ }
+ xch->xch_start_time = ddi_get_lbolt();
+ do {
+ xch->xch_rxid = atomic_add_16_nv(
+ &xch->xch_ss->ss_next_unsol_rxid, 1);
+ if (xch->xch_rxid == 0xFFFF) {
+ xch->xch_rxid = atomic_add_16_nv(
+ &xch->xch_ss->ss_next_unsol_rxid, 1);
+ }
+ } while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash,
+ (mod_hash_key_t)(intptr_t)xch->xch_rxid,
+ (mod_hash_val_t)&xch_tmp) == 0);
+
+ xch->xch_sequence_no = 0;
+ xch->xch_ref = 0;
+ (void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash,
+ (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch);
+ xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
+
+ /*
+ * cmd initialization
+ */
+ cmd->cmd_port = FRM2SS(frm)->ss_port;
+ cmd->cmd_rp_handle = FCT_HANDLE_NONE;
+ cmd->cmd_rportid = FRM_S_ID(frm);
+ cmd->cmd_lportid = FRM_D_ID(frm);
+ cmd->cmd_oxid = xch->xch_oxid;
+ cmd->cmd_rxid = xch->xch_rxid;
+
+ fcoet_init_tfm(frm, xch);
+ return (xch);
+}
+
+int
+fcoet_clear_unsol_exchange(fcoet_exchange_t *xch)
+{
+ mod_hash_val_t val = NULL;
+
+ if (mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
+ (mod_hash_key_t)(intptr_t)xch->xch_rxid, &val) == 0) {
+ if (xch->xch_dbuf_num) {
+ kmem_free((void*)xch->xch_dbufs,
+ xch->xch_dbuf_num * sizeof (void *));
+ xch->xch_dbufs = NULL;
+ xch->xch_dbuf_num = 0;
+ }
+ ASSERT(xch->xch_flags & XCH_FLAG_IN_HASH_TABLE);
+ ASSERT((fcoet_exchange_t *)val == xch);
+ xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
+ return (FCOE_SUCCESS);
+ }
+
+ FCOET_LOG("fcoet_clear_unsol_exchange", "xch %p already cleared from "
+ "hash table", xch);
+ return (FCOE_FAILURE);
+}
+
+void
+fcoet_clear_sol_exchange(fcoet_exchange_t *xch)
+{
+ mod_hash_val_t val = NULL;
+
+ if (xch->xch_flags & XCH_FLAG_IN_HASH_TABLE) {
+ (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
+ (mod_hash_key_t)(intptr_t)xch->xch_oxid, &val);
+ ASSERT((fcoet_exchange_t *)val == xch);
+ xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
+ }
+}
+
+static int
+fcoet_process_sol_fcp_data(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = NULL;
+ fcoet_soft_state_t *ss = NULL;
+ fct_status_t fc_st;
+ uint32_t iof;
+ uint16_t unsol_rxid;
+ int sge_idx;
+ stmf_data_buf_t *dbuf;
+ int data_offset;
+
+ unsol_rxid = FRM_RXID(frm);
+ if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
+ (mod_hash_key_t)(intptr_t)unsol_rxid,
+ (mod_hash_val_t)&xch, fcoet_modhash_find_cb) != 0) {
+ return (FCOE_FAILURE);
+ }
+
+ /*
+ * we will always have a buf waiting there
+ */
+ data_offset = FRM_PARAM(frm);
+ dbuf = xch->xch_dbufs[data_offset/FCOET_MAX_DBUF_LEN];
+ ASSERT(dbuf);
+ ss = xch->xch_ss;
+ sge_idx = (data_offset % FCOET_MAX_DBUF_LEN)/
+ ss->ss_fcp_data_payload_size;
+
+ ASSERT(((sge_idx < FCOET_GET_SEG_NUM(dbuf) - 1) &&
+ (frm->frm_payload_size == ss->ss_fcp_data_payload_size)) ||
+ ((sge_idx == FCOET_GET_SEG_NUM(dbuf) - 1) &&
+ (frm->frm_payload_size % ss->ss_fcp_data_payload_size ==
+ dbuf->db_data_size % ss->ss_fcp_data_payload_size)));
+
+ bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr,
+ frm->frm_payload_size);
+
+ xch->xch_left_data_size -= frm->frm_payload_size;
+ if (xch->xch_left_data_size <= 0) {
+ fc_st = FCT_SUCCESS;
+ iof = 0;
+ dbuf->db_xfer_status = fc_st;
+ dbuf->db_flags |= DB_DONT_REUSE;
+ fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
+ }
+
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch;
+ fcoe_fcp_cmnd_t *ffc;
+ uint8_t tm;
+ scsi_task_t *task;
+
+ xch = fcoet_create_unsol_exchange(frm);
+ if (xch == NULL) {
+ FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange");
+ return (FCOE_FAILURE);
+ }
+
+ ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload;
+ task = XCH2TASK(xch);
+ task->task_csn_size = 8;
+ task->task_max_nbufs = 1;
+ task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num);
+ task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07;
+ task->task_flags |=
+ (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5;
+ task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl);
+
+ tm = FCOE_B2V_1(ffc->ffc_management_flags);
+ if (tm) {
+ if (tm & BIT_1) {
+ task->task_mgmt_function = TM_ABORT_TASK_SET;
+ } else if (tm & BIT_2) {
+ task->task_mgmt_function = TM_CLEAR_TASK_SET;
+ } else if (tm & BIT_4) {
+ task->task_mgmt_function = TM_LUN_RESET;
+ } else if (tm & BIT_5) {
+ task->task_mgmt_function = TM_TARGET_COLD_RESET;
+ } else if (tm & BIT_6) {
+ task->task_mgmt_function = TM_CLEAR_ACA;
+ } else {
+ task->task_mgmt_function = TM_ABORT_TASK;
+ }
+ }
+
+ bcopy(ffc->ffc_cdb, task->task_cdb, 16);
+ fct_post_rcvd_cmd(xch->xch_cmd, NULL);
+ return (FCOE_SUCCESS);
+}
+/*
+ * It must be from link
+ * req_payload has been allocated when create_unsol_exchange
+ */
+static int
+fcoet_process_unsol_els_req(fcoe_frame_t *frm)
+{
+ int ret = FCOE_SUCCESS;
+ fcoet_exchange_t *xch;
+
+ xch = fcoet_create_unsol_exchange(frm);
+ ASSERT(xch);
+ ASSERT(FRM_IS_LAST_FRAME(frm));
+
+ /*
+ * For the reason of keeping symmetric, we do copy here as in
+ * process_sol_els instead of in create_unsol_exchange.
+ * req_payload depends on how to allocate buf in create_unsol_exchange
+ */
+ XCH2ELS(xch)->els_req_alloc_size = 0;
+ XCH2ELS(xch)->els_req_size = frm->frm_payload_size;
+ XCH2ELS(xch)->els_req_payload =
+ GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t));
+ bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload,
+ XCH2ELS(xch)->els_req_size);
+ if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
+ /*
+ * Ensure LINK_UP event has been handled, or PLOIG has
+ * been processed by FCT, or else it will be discarded.
+ * It need more consideration later ???
+ */
+ if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) &&
+ (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
+ delay(STMF_SEC2TICK(1)/2);
+ }
+
+ if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) &&
+ (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) {
+ atomic_and_32(&xch->xch_ss->ss_flags,
+ ~SS_FLAG_DELAY_PLOGI);
+ delay(STMF_SEC2TICK(1)/3);
+ }
+ fct_post_rcvd_cmd(xch->xch_cmd, NULL);
+ } else {
+ /*
+ * We always handle FLOGI internally
+ * Save dst mac address from FLOGI request to restore later
+ */
+ bcopy((char *)frm->frm_hdr-22,
+ frm->frm_eport->eport_efh_dst, ETHERADDRL);
+ ret = fcoet_process_unsol_flogi_req(xch);
+ }
+ return (ret);
+}
+
+
+/*
+ * It must be from link, but could be incomplete because of network problems
+ */
+static int
+fcoet_process_sol_els_rsp(fcoe_frame_t *frm)
+{
+ uint32_t actual_size;
+ fct_status_t fc_st;
+ uint32_t iof;
+ uint16_t sol_oxid;
+ fcoet_exchange_t *xch = NULL;
+ fct_els_t *els = NULL;
+ int ret = FCOE_SUCCESS;
+
+ sol_oxid = FRM_OXID(frm);
+ if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(intptr_t)sol_oxid,
+ (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
+ return (FCOE_FAILURE);
+ }
+ if (xch != FRM2SS(frm)->ss_sol_flogi) {
+ fcoet_clear_sol_exchange(xch);
+ }
+
+ fcoet_init_tfm(frm, xch);
+ els = CMD2ELS(xch->xch_cmd);
+ ASSERT(FRM_IS_LAST_FRAME(frm));
+ actual_size = els->els_resp_size;
+ if (actual_size > frm->frm_payload_size) {
+ actual_size = frm->frm_payload_size;
+ }
+
+ els->els_resp_size = (uint16_t)actual_size;
+ bcopy(frm->frm_payload, els->els_resp_payload, actual_size);
+
+ if (xch->xch_ss->ss_sol_flogi == xch) {
+ /*
+ * We handle FLOGI internally
+ */
+ ret = fcoet_process_sol_flogi_rsp(frm);
+ FCOET_RELE_XCHG(xch);
+ } else {
+ fc_st = FCT_SUCCESS;
+ iof = FCT_IOF_FCA_DONE;
+ FCOET_RELE_XCHG(xch);
+ fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
+ }
+ return (ret);
+}
+
+/*
+ * It's still in the context of being aborted exchange, but FCT can't support
+ * this scheme, so there are two fct_cmd_t that are bound with one exchange.
+ */
+static int
+fcoet_process_unsol_abts_req(fcoe_frame_t *frm)
+{
+ fct_cmd_t *cmd;
+ fcoet_exchange_t *xch = NULL;
+ uint16_t unsol_rxid;
+
+ FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x",
+ FRM_OXID(frm), FRM_RXID(frm));
+ unsol_rxid = FRM_RXID(frm);
+ if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash,
+ (mod_hash_key_t)(intptr_t)unsol_rxid,
+ (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) {
+ FCOET_LOG("fcoet_process_unsol_abts_req",
+ "can't find aborted exchange");
+ return (FCOE_SUCCESS);
+ }
+
+ fcoet_init_tfm(frm, xch);
+ if (!FRM_IS_LAST_FRAME(frm)) {
+ FCOET_LOG("fcoet_process_unsol_abts_req",
+ "not supported this kind frame");
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_FAILURE);
+ }
+
+ cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0);
+ if (cmd == NULL) {
+ FCOET_LOG("fcoet_process_unsol_abts_req",
+ "can't alloc fct_cmd_t");
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_FAILURE);
+ }
+
+ xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT;
+ cmd->cmd_fca_private = xch;
+ cmd->cmd_port = xch->xch_cmd->cmd_port;
+ cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle;
+ cmd->cmd_rportid = xch->xch_cmd->cmd_rportid;
+ cmd->cmd_lportid = xch->xch_cmd->cmd_lportid;
+ cmd->cmd_oxid = xch->xch_cmd->cmd_oxid;
+ cmd->cmd_rxid = xch->xch_cmd->cmd_rxid;
+ fct_post_rcvd_cmd(cmd, NULL);
+ FCOET_LOG("fcoet_process_unsol_abts_req",
+ "abts now: xch/%p, frm/%p - time/%p",
+ xch, frm, ddi_get_lbolt());
+
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_sol_abts_acc(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = NULL;
+ uint16_t sol_oxid;
+
+ sol_oxid = FRM_OXID(frm);
+ if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(intptr_t)sol_oxid,
+ (mod_hash_val_t *)&xch) != 0) {
+ /*
+ * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
+ * in fcoet_watch_handle_sol_flogi, Will improve it later
+ */
+ return (FCOE_SUCCESS);
+ }
+
+ xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
+ if (!FRM_IS_LAST_FRAME(frm)) {
+ FCOET_LOG("fcoet_process_sol_abts_acc",
+ "not supported this kind frame");
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_FAILURE);
+ }
+ FCOET_LOG("fcoet_process_sol_abts_acc",
+ "ABTS received but there is nothing to do");
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_sol_abts_rjt(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = NULL;
+ uint16_t sol_oxid;
+
+ sol_oxid = FRM_OXID(frm);
+ if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(intptr_t)sol_oxid,
+ (mod_hash_val_t *)&xch) != 0) {
+ /*
+ * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash
+ * in fcoet_watch_handle_sol_flogi, Will improve it later
+ */
+ return (FCOE_SUCCESS);
+ }
+
+ xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
+
+ if (!FRM_IS_LAST_FRAME(frm)) {
+ FCOET_LOG("fcoet_process_sol_abts_rjt",
+ "not supported this kind frame");
+ return (FCOE_FAILURE);
+ }
+
+ FCOET_LOG("fcoet_process_sol_abts_rjt",
+ "ABTS_RJT received rjt reason %x but there is nothing to do",
+ frm->frm_payload[1]);
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_unsol_ct_req(fcoe_frame_t *frm)
+{
+ /*
+ * If you want to implement virtual name server, or FC/ETH
+ * gateway, you can do it here
+ */
+ if (!FRM_IS_LAST_FRAME(frm)) {
+ FCOET_LOG("fcoet_process_unsol_ct_req",
+ "not supported this kind frame");
+ return (FCOE_FAILURE);
+ }
+
+ FCOET_LOG("fcoet_process_unsol_ct_req",
+ "No support for unsolicited CT request");
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_sol_ct_rsp(fcoe_frame_t *frm)
+{
+ uint32_t actual_size;
+ fct_status_t fc_st;
+ uint32_t iof;
+ fct_sol_ct_t *ct = NULL;
+ fcoet_exchange_t *xch = NULL;
+ uint16_t sol_oxid;
+
+ sol_oxid = FRM_OXID(frm);
+
+ if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(intptr_t)sol_oxid,
+ (mod_hash_val_t *)&xch) != 0) {
+ return (FCOE_SUCCESS);
+ }
+
+ xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE;
+ fcoet_init_tfm(frm, xch);
+
+ ASSERT(FRM_IS_LAST_FRAME(frm));
+ actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size;
+ if (actual_size > frm->frm_payload_size) {
+ actual_size = frm->frm_payload_size;
+ }
+ ct = CMD2CT(xch->xch_cmd);
+ ct->ct_resp_size = (uint16_t)actual_size;
+
+ bcopy(frm->frm_payload,
+ CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size);
+
+ fc_st = FCT_SUCCESS;
+ iof = FCT_IOF_FCA_DONE;
+ fct_send_cmd_done(xch->xch_cmd, fc_st, iof);
+
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch;
+ stmf_data_buf_t *dbuf;
+ int dbuf_index;
+ uint32_t iof;
+
+ dbuf_index = FRM2TFM(frm)->tfm_buf_idx;
+ xch->xch_left_data_size -= frm->frm_payload_size;
+ dbuf = xch->xch_dbufs[dbuf_index];
+ ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT));
+
+ /*
+ * We decrease db_sglist_length only for READ-type commands.
+ * For INQUIRY, resid could be non-zero, then db_sglist_length will
+ * be useful.
+ */
+ dbuf->db_sglist_length--;
+ if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) {
+ iof = 0;
+ dbuf->db_xfer_status = FCT_SUCCESS;
+ dbuf->db_flags |= DB_DONT_REUSE;
+ if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
+ if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) {
+ return (FCOE_FAILURE);
+ }
+ } else {
+ fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof);
+ }
+ }
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_send_fcp_status_done(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch;
+ fct_status_t fc_st = FCT_SUCCESS;
+ uint32_t iof = FCT_IOF_FCA_DONE;
+
+ if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+ }
+
+ if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) {
+ FCOET_RELE_XCHG(xch);
+ fct_send_response_done(xch->xch_cmd, fc_st, iof);
+ } else {
+ /* Already cleared from hash table by abort */
+ FCOET_RELE_XCHG(xch);
+ }
+
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * Solicited frames callback area
+ */
+static int
+fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm)
+{
+ fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch;
+ fct_status_t fc_st;
+ uint32_t iof;
+
+ FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done",
+ "frm/oxid/els: %p/%x/%x",
+ frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]);
+ if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+ }
+
+ if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) {
+ FCOET_RELE_XCHG(xch);
+ return (FCOE_SUCCESS);
+ }
+
+ FCOET_RELE_XCHG(xch);
+ if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) {
+ fc_st = FCT_SUCCESS;
+ iof = FCT_IOF_FCA_DONE;
+ fct_send_response_done(xch->xch_cmd, fc_st, iof);
+ } else {
+ /*
+ * We need update ss_link_info and flags.
+ */
+ mutex_enter(&xch->xch_ss->ss_watch_mutex);
+ xch->xch_ss->ss_link_info.portid =
+ xch->xch_cmd->cmd_lportid;
+ xch->xch_ss->ss_link_info.port_topology =
+ PORT_TOPOLOGY_PT_TO_PT;
+ if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
+ xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G;
+ } else if (frm->frm_eport->eport_link_speed ==
+ FCOE_PORT_SPEED_10G) {
+ xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
+ }
+ xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
+ xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
+ xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
+ bcopy(XCH2ELS(xch)->els_req_payload + 20,
+ xch->xch_ss->ss_link_info.port_rpwwn, 8);
+ bcopy(XCH2ELS(xch)->els_req_payload + 28,
+ xch->xch_ss->ss_link_info.port_rnwwn, 8);
+ atomic_or_32(&xch->xch_ss->ss_flags,
+ SS_FLAG_UNSOL_FLOGI_DONE);
+ atomic_or_32(&xch->xch_ss->ss_flags,
+ SS_FLAG_REPORT_TO_FCT);
+
+ xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
+ mutex_exit(&xch->xch_ss->ss_watch_mutex);
+
+ fct_free(xch->xch_cmd);
+ }
+ return (FCOE_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+fcoet_send_sol_els_req_done(fcoe_frame_t *frm)
+{
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not
+ * needed to notify FCT anything. Just do nothing.
+ */
+/* ARGSUSED */
+static int
+fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm)
+{
+ FCOET_LOG("fcoet_send_unsol_bls_acc_done",
+ "Unsolicited BA_ACC sent out and released ");
+
+ return (FCOE_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm)
+{
+ FCOET_LOG("fcoet_send_unsol_bls_rjt_done",
+ "Unsolicited BA_RJT sent out and released");
+ return (FCOE_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+fcoet_send_sol_bls_req_done(fcoe_frame_t *frm)
+{
+ FCOET_LOG("fcoet_send_sol_bls_req_done",
+ "Soclited ABTS was sent out and released");
+ return (FCOE_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+fcoet_send_sol_ct_req_done(fcoe_frame_t *frm)
+{
+ FCOET_LOG("fcoet_send_sol_ct_req_done",
+ "CT request was sent out and released");
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * FCoET can only interpret solicited and unsolicited FLOGI, all the other
+ * ELS/CT/FCP should be passed up to FCT.
+ */
+static int
+fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch)
+{
+ fcoe_frame_t *frm;
+
+ atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI);
+
+ /*
+ * In spec, common service parameter should indicate if it's from
+ * N-port or F-port, but the initial intel implementation is not
+ * spec-compliant, so we use eport_flags to workaround the problem
+ */
+ if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) {
+ /*
+ * The topology is switch P2P, so there's no need to respond
+ * to this FLOGI
+ */
+ FCOET_LOG("fcoet_process_unsol_flogi_req",
+ "skip FLOGI, since we are in switch topology");
+ return (FCOE_SUCCESS);
+ }
+
+ /*
+ * Send ACC according to the spec.
+ */
+ frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+ FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCOE_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, xch);
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+
+ FFM_R_CTL(0x23, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x23;
+ FFM_TYPE(0x01, frm);
+ FFM_F_CTL(0x980000, frm);
+ FFM_OXID(xch->xch_oxid, frm);
+ FFM_RXID(xch->xch_rxid, frm);
+ FFM_S_ID(0xFFFFFE, frm);
+
+ /*
+ * ACC
+ */
+ frm->frm_payload[0] = 0x02;
+
+ /*
+ * Common Svc Parameters
+ */
+ frm->frm_payload[4] = 0x20;
+ frm->frm_payload[5] = 0x20;
+ frm->frm_payload[7] = 0x0A;
+ frm->frm_payload[10] = 0x05;
+ frm->frm_payload[11] = 0xAC;
+ bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8);
+ bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8);
+
+ /*
+ * Class3 Svc Parameters
+ */
+ frm->frm_payload[68] = 0x88;
+
+ /*
+ * Send FLOGI ACC out
+ * After this, we should never use the exchange, because it could
+ * have been released. Please pay attention to other similiar cases.
+ */
+ xch->xch_ss->ss_eport->eport_tx_frame(frm);
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm)
+{
+ int ret = FCOE_SUCCESS;
+ fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch;
+ fct_els_t *els = CMD2ELS(xch->xch_cmd);
+
+ if (els->els_resp_payload[0] == ELS_OP_ACC) {
+ /*
+ * We need always update ss_link_info and flags for solicited
+ * FLOGI, because someone has assigned address for you. The
+ * initial intel implementation will always assign address for
+ * you even you are in back-to-back mode (direct P2P).
+ */
+ mutex_enter(&xch->xch_ss->ss_watch_mutex);
+ if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) {
+ xch->xch_cmd->cmd_lportid = FRM_D_ID(frm);
+ xch->xch_ss->ss_link_info.portid =
+ xch->xch_cmd->cmd_lportid;
+ /*
+ * Check the bit 28 in 3rd word of the payload
+ * in common service parameters to know the
+ * remote port is F_PORT or N_PORT
+ */
+ if (els->els_resp_payload[8] & 0x10) {
+ 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);
+ bcopy((char *)frm->frm_hdr-22,
+ frm->frm_eport->eport_efh_dst,
+ ETHERADDRL);
+ frm->frm_eport->eport_set_mac_address(
+ frm->frm_eport, src_addr, B_TRUE);
+ xch->xch_ss->ss_link_info.port_topology =
+ PORT_TOPOLOGY_FABRIC_PT_TO_PT;
+ } else {
+ xch->xch_ss->ss_link_info.port_topology =
+ PORT_TOPOLOGY_PT_TO_PT;
+ }
+
+ xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G;
+ xch->xch_ss->ss_link_info.port_no_fct_flogi = 1;
+ xch->xch_ss->ss_link_info.port_fca_flogi_done = 1;
+ xch->xch_ss->ss_link_info.port_fct_flogi_done = 0;
+ xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC;
+ cv_signal(&xch->xch_ss->ss_watch_cv);
+ FCOET_LOG("fcoet_process_sol_flogi_rsp",
+ "FLOGI is accecpted");
+ } else {
+ FCOET_LOG("fcoet_process_sol_flogi_rsp",
+ "FLOGI xch_flags/%x", xch->xch_flags);
+ ret = FCOE_FAILURE;
+ }
+ mutex_exit(&xch->xch_ss->ss_watch_mutex);
+ } else {
+ FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected");
+ ret = FCOE_FAILURE;
+ }
+ return (ret);
+}
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h
new file mode 100644
index 0000000000..87a25296c5
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.h
@@ -0,0 +1,46 @@
+/*
+ * 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 _FCOET_ETH_H
+#define _FCOET_ETH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+void fcoet_rx_frame(fcoe_frame_t *frame);
+void fcoet_port_event(fcoe_port_t *eport, uint32_t event);
+void fcoet_release_sol_frame(fcoe_frame_t *frame);
+int fcoet_clear_unsol_exchange(fcoet_exchange_t *xch);
+void fcoet_clear_sol_exchange(fcoet_exchange_t *xch);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOET_ETH_H */
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
new file mode 100644
index 0000000000..86e97006ee
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c
@@ -0,0 +1,1053 @@
+/*
+ * 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 fct driver.
+ */
+
+/*
+ * 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/modhash.h>
+#include <sys/scsi/scsi.h>
+#include <sys/ethernet.h>
+
+/*
+ * COMSTAR header files
+ */
+#include <sys/stmf_defines.h>
+#include <sys/fct_defines.h>
+#include <sys/stmf.h>
+#include <sys/portif.h>
+#include <sys/fct.h>
+
+/*
+ * FCoE hader files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoet.h>
+#include <fcoet_fc.h>
+#include <fcoet_eth.h>
+
+/*
+ * function forward declaration
+ */
+static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port,
+ fct_remote_port_t *rp, fct_cmd_t *login);
+static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port,
+ fct_remote_port_t *rp, fct_cmd_t *login);
+static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd);
+static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd);
+static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd);
+static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd);
+static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags);
+static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss);
+
+/*
+ * Return the lower link information
+ */
+fct_status_t
+fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
+{
+ bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t));
+ return (FCT_SUCCESS);
+}
+
+/*
+ * FCT will call this, when it wants to send PLOGI or has received PLOGI.
+ */
+fct_status_t
+fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
+ fct_cmd_t *login)
+{
+ uint16_t handle;
+ fct_status_t ret;
+
+ switch (rp->rp_id) {
+ case 0xFFFFFC:
+ handle = 0x7FC;
+ break;
+
+ case 0xFFFFFD:
+ handle = 0x7FD;
+ break;
+
+ case 0xFFFFFE:
+ handle = 0x7FE;
+ break;
+
+ case 0xFFFFFF:
+ handle = 0x7FF;
+ break;
+
+ default:
+ /*
+ * For not well-known address, we let FCT to select one.
+ */
+ handle = FCT_HANDLE_NONE;
+ break;
+ }
+
+ rp->rp_handle = handle;
+ if (login->cmd_type == FCT_CMD_SOL_ELS) {
+ ret = fcoet_fill_plogi_req(port, rp, login);
+ } else {
+ ret = fcoet_fill_plogi_resp(port, rp, login);
+ }
+
+ return (ret);
+}
+
+/*
+ * FCT will call this to say "FCoET can release resources with this RP now."
+ */
+/* ARGSUSED */
+fct_status_t
+fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
+{
+ fcoet_soft_state_t *this_ss = PORT2SS(port);
+
+ this_ss->ss_rport_dereg_state = 0;
+ this_ss->ss_rportid_in_dereg = 0;
+ return (FCT_SUCCESS);
+}
+
+fct_status_t
+fcoet_send_cmd(fct_cmd_t *cmd)
+{
+ if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
+ return (fcoet_send_sol_els(cmd));
+ } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
+ return (fcoet_send_sol_ct(cmd));
+ }
+
+ return (FCT_FAILURE);
+}
+
+/*
+ * SCSI response phase
+ * ELS_ACC/ELS_RJT
+ */
+fct_status_t
+fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
+{
+ char info[160];
+
+ if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
+ if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
+ goto send_cmd_rsp_error;
+ } else {
+ return (fcoet_send_status(cmd));
+ }
+ }
+
+ if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
+ if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
+ goto send_cmd_rsp_error;
+ } else {
+ return (fcoet_send_els_response(cmd));
+ }
+ }
+
+ if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
+ cmd->cmd_handle = 0;
+ }
+
+ if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
+ return (fcoet_send_abts_response(cmd, 0));
+ } else {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ }
+
+send_cmd_rsp_error:
+ (void) snprintf(info, 160, "fcoet_send_cmd_response: can not handle "
+ "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", cmd, ioflags);
+ info[159] = 0;
+ (void) fct_port_shutdown(CMD2SS(cmd)->ss_port,
+ STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
+ return (FCT_FAILURE);
+}
+
+/*
+ * It's for read/write (xfer_rdy)
+ */
+/* ARGSUSED */
+fct_status_t
+fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
+{
+ fcoe_frame_t *frm;
+ int idx;
+ int frm_num;
+ int data_size;
+ int left_size;
+ int offset;
+ fcoet_exchange_t *xch = CMD2XCH(cmd);
+
+ ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]);
+ xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf;
+
+ left_size = (int)dbuf->db_data_size;
+ if (dbuf->db_relative_offset == 0)
+ xch->xch_left_data_size =
+ XCH2TASK(xch)->task_expected_xfer_length;
+
+ if (dbuf->db_flags == DB_DIRECTION_FROM_RPORT) {
+ /*
+ * If it's write type command, we need send xfer_rdy now
+ * We may need to consider bidirectional command later
+ */
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
+ CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) +
+ FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+
+ FFM_R_CTL(0x05, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x05;
+ FFM_TYPE(0x08, frm);
+ FFM_F_CTL(0x890000, frm);
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload);
+ FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+ }
+
+ /*
+ * It's time to transfer READ data to remote side
+ */
+ frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size -
+ 1) / CMD2SS(cmd)->ss_fcp_data_payload_size;
+ offset = dbuf->db_relative_offset;
+ for (idx = 0; idx < frm_num; idx++) {
+ if (idx == (frm_num -1)) {
+ data_size = P2ROUNDUP(left_size, 4);
+ } else {
+ data_size = CMD2SS(cmd)->ss_fcp_data_payload_size;
+ }
+
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
+ CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE,
+ FCOET_GET_NETB(dbuf, idx));
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ /*
+ * lock the xchg to avoid being released (by abort)
+ * after sent out and before release
+ */
+ FCOET_BUSY_XCHG(CMD2XCH(cmd));
+ }
+
+ FFM_R_CTL(0x01, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x01;
+ FRM2TFM(frm)->tfm_buf_idx =
+ dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN;
+ FFM_TYPE(0x08, frm);
+ if (idx != frm_num - 1) {
+ FFM_F_CTL(0x800008, frm);
+ } else {
+ FFM_F_CTL(0x880008, frm);
+ }
+
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ FFM_SEQ_CNT(xch->xch_sequence_no, frm);
+ atomic_add_8(&xch->xch_sequence_no, 1);
+ FFM_PARAM(offset, frm);
+ offset += data_size;
+ left_size -= data_size;
+
+ /*
+ * Disassociate netbs which will be freed by NIC driver
+ */
+ FCOET_SET_NETB(dbuf, idx, NULL);
+
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+ }
+
+ return (FCT_SUCCESS);
+}
+
+fct_status_t
+fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
+{
+ fcoet_soft_state_t *this_ss = PORT2SS(port);
+ fct_status_t fct_ret = FCT_SUCCESS;
+
+ FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p",
+ cmd, cmd->cmd_fca_private, cmd->cmd_specific);
+ switch (cmd->cmd_type) {
+ case FCT_CMD_RCVD_ABTS:
+ /*
+ * Sometimes unsolicited ABTS request will be received twice
+ * and the first ABTS is not done yet, so the second ABTS
+ * will be passed down here, in this case we will do
+ * nothing and abts response is not needed to be sent
+ * fct_ret = fcoet_send_abts_response(cmd, 1);
+ */
+ break;
+ case FCT_CMD_FCP_XCHG:
+ case FCT_CMD_RCVD_ELS:
+ if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ break;
+ }
+
+ CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
+ (void) fcoet_clear_unsol_exchange(CMD2XCH(cmd));
+ if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
+ mutex_enter(&this_ss->ss_watch_mutex);
+ CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
+ list_insert_tail(&this_ss->ss_abort_xchg_list,
+ CMD2XCH(cmd));
+ cv_signal(&this_ss->ss_watch_cv);
+ mutex_exit(&this_ss->ss_watch_mutex);
+ }
+ break;
+
+ case FCT_CMD_SOL_ELS:
+ case FCT_CMD_SOL_CT:
+ if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
+ break;
+ }
+
+ CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
+ fcoet_clear_sol_exchange(CMD2XCH(cmd));
+
+ if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
+ mutex_enter(&this_ss->ss_watch_mutex);
+ CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
+ cv_signal(&this_ss->ss_watch_cv);
+ list_insert_tail(&this_ss->ss_abort_xchg_list,
+ CMD2XCH(cmd));
+ mutex_exit(&this_ss->ss_watch_mutex);
+ }
+
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ if ((flags & FCT_IOF_FORCE_FCA_DONE) &&
+ (cmd->cmd_type != FCT_CMD_FCP_XCHG)) {
+ cmd->cmd_handle = 0;
+ }
+
+ return (fct_ret);
+}
+
+/* ARGSUSED */
+fct_status_t
+fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
+{
+ cmn_err(CE_WARN, "FLOGI requested (not supported)");
+ return (FCT_FAILURE);
+}
+
+void
+fcoet_send_sol_flogi(fcoet_soft_state_t *ss)
+{
+ fcoet_exchange_t *xch;
+ fct_cmd_t *cmd;
+ fct_els_t *els;
+ fcoe_frame_t *frm;
+
+ /*
+ * FCT will initialize fct_cmd_t
+ * Initialize fcoet_exchange
+ */
+ cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
+ sizeof (fcoet_exchange_t), 0);
+ xch = CMD2XCH(cmd);
+ els = CMD2ELS(cmd);
+
+ xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
+ if (xch->xch_oxid == 0xFFFF) {
+ xch->xch_oxid =
+ atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
+ }
+ xch->xch_rxid = 0xFFFF;
+ xch->xch_flags = 0;
+ xch->xch_ss = ss;
+ xch->xch_cmd = cmd;
+ xch->xch_current_seq = NULL;
+ xch->xch_start_time = ddi_get_lbolt();
+
+ /*
+ * Keep it to compare with response
+ */
+ ss->ss_sol_flogi = xch;
+ els->els_resp_alloc_size = 116;
+ els->els_resp_size = 116;
+ els->els_resp_payload = (uint8_t *)
+ kmem_zalloc(els->els_resp_size, KM_SLEEP);
+ (void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash,
+ (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
+ xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
+ atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI);
+
+ /*
+ * FCoE will initialize fcoe_frame_t
+ */
+ frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
+ FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return;
+ } else {
+ fcoet_init_tfm(frm, xch);
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+
+ FFM_R_CTL(0x22, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x22;
+ FFM_TYPE(0x01, frm);
+ FFM_F_CTL(0x290000, frm);
+ FFM_OXID(xch->xch_oxid, frm);
+ FFM_RXID(xch->xch_rxid, frm);
+ FFM_D_ID(0xfffffe, frm);
+ frm->frm_payload[0] = ELS_OP_FLOGI;
+ /* Common Service Parameters */
+ frm->frm_payload[4] = 0x20;
+ frm->frm_payload[5] = 0x08;
+ frm->frm_payload[6] = 0x0;
+ frm->frm_payload[7] = 0x03;
+ /* N_PORT */
+ frm->frm_payload[8] = 0x88;
+ frm->frm_payload[9] = 0x00;
+ frm->frm_payload[10] = 0x08;
+ frm->frm_payload[11] = 0x0;
+ frm->frm_payload[12] = 0x0;
+ frm->frm_payload[13] = 0xff;
+ frm->frm_payload[14] = 0x0;
+ frm->frm_payload[15] = 0x03;
+ frm->frm_payload[16] = 0x0;
+ frm->frm_payload[17] = 0x0;
+ frm->frm_payload[18] = 0x07;
+ frm->frm_payload[19] = 0xd0;
+ /* PWWN and NWWN */
+ frm->frm_payload[20] = 0x0;
+ bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8);
+ bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8);
+ /* Class 3 Service Parameters */
+ frm->frm_payload[68] = 0x88;
+ frm->frm_payload[74] = 0x08;
+ frm->frm_payload[77] = 0xff;
+
+ ss->ss_eport->eport_tx_frame(frm);
+ xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT;
+}
+
+/*
+ * This is for solicited FLOGI only
+ */
+void
+fcoet_send_sol_abts(fcoet_exchange_t *xch)
+{
+ fcoe_frame_t *frm;
+ fcoet_soft_state_t *ss = xch->xch_ss;
+
+ /*
+ * FCoE will initialize fcoe_frame_t
+ * ABTS has no payload
+ */
+ frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
+ FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return;
+ } else {
+ fcoet_init_tfm(frm, xch);
+ frm->frm_payload = NULL;
+ }
+
+ FFM_R_CTL(0x81, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x81;
+ FFM_F_CTL(0x090000, frm);
+ FFM_OXID(xch->xch_oxid, frm);
+ FFM_RXID(xch->xch_rxid, frm);
+ FFM_D_ID(0xfffffe, frm);
+ FFM_SEQ_CNT(xch->xch_sequence_no, frm);
+ xch->xch_start_time = ddi_get_lbolt();
+
+ ss->ss_eport->eport_tx_frame(frm);
+}
+
+void
+fcoet_ctl(struct fct_local_port *port, int cmd, void *arg)
+{
+ stmf_change_status_t st;
+ stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg;
+ fcoet_soft_state_t *this_ss = PORT2SS(port);
+
+ st.st_completion_status = FCT_SUCCESS;
+ st.st_additional_info = NULL;
+
+ switch (cmd) {
+ case FCT_CMD_PORT_ONLINE:
+ if (this_ss->ss_state == FCT_STATE_ONLINE)
+ st.st_completion_status = STMF_ALREADY;
+ else if (this_ss->ss_state != FCT_STATE_OFFLINE)
+ st.st_completion_status = FCT_FAILURE;
+ if (st.st_completion_status == FCT_SUCCESS) {
+ this_ss->ss_state = FCT_STATE_ONLINING;
+ this_ss->ss_state_not_acked = 1;
+ st.st_completion_status = fcoet_enable_port(this_ss);
+ if (st.st_completion_status != STMF_SUCCESS) {
+ this_ss->ss_state = FCT_STATE_OFFLINE;
+ this_ss->ss_state_not_acked = 0;
+ } else {
+ this_ss->ss_state = FCT_STATE_ONLINE;
+ }
+ }
+ fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
+ this_ss->ss_change_state_flags = 0;
+ break;
+
+ case FCT_CMD_PORT_OFFLINE:
+ if (this_ss->ss_state == FCT_STATE_OFFLINE) {
+ st.st_completion_status = STMF_ALREADY;
+ } else if (this_ss->ss_state != FCT_STATE_ONLINE) {
+ st.st_completion_status = FCT_FAILURE;
+ }
+ if (st.st_completion_status == FCT_SUCCESS) {
+ this_ss->ss_state = FCT_STATE_OFFLINING;
+ this_ss->ss_state_not_acked = 1;
+ this_ss->ss_change_state_flags = ssci->st_rflags;
+ st.st_completion_status = fcoet_disable_port(this_ss);
+ if (st.st_completion_status != STMF_SUCCESS) {
+ this_ss->ss_state = FCT_STATE_ONLINE;
+ this_ss->ss_state_not_acked = 0;
+ } else {
+ this_ss->ss_state = FCT_STATE_OFFLINE;
+ }
+ }
+ fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
+ break;
+
+ case FCT_ACK_PORT_ONLINE_COMPLETE:
+ this_ss->ss_state_not_acked = 0;
+ break;
+
+ case FCT_ACK_PORT_OFFLINE_COMPLETE:
+ this_ss->ss_state_not_acked = 0;
+ if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) {
+ if (fct_port_initialize(port,
+ this_ss->ss_change_state_flags,
+ "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
+ "with RLFLAG_RESET") != FCT_SUCCESS) {
+ cmn_err(CE_WARN, "fcoet_ctl: "
+ "fct_port_initialize %s failed",
+ this_ss->ss_alias);
+ FCOET_LOG("fcoet_ctl: fct_port_initialize "
+ "%s failed", this_ss->ss_alias);
+ }
+ }
+ break;
+ default:
+ FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd);
+ break;
+ }
+}
+
+/*
+ * Filling the hba attributes
+ */
+/* ARGSUSED */
+void
+fcoet_populate_hba_fru_details(struct fct_local_port *port,
+ struct fct_port_attrs *port_attrs)
+{
+ (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
+ "Sun Microsystems, Inc.");
+ (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
+ "%s", FCOET_NAME);
+ (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
+ "%s", FCOET_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 = 2136;
+ port_attrs->supported_cos = 0x10000000;
+ /* Specified a fix speed here, need to change it in the future */
+ port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G;
+}
+
+
+static fct_status_t
+fcoet_send_sol_els(fct_cmd_t *cmd)
+{
+ fcoe_frame_t *frm;
+ fcoet_exchange_t *xch = NULL;
+
+ xch = CMD2XCH(cmd);
+ xch->xch_flags = 0;
+ xch->xch_ss = CMD2SS(cmd);
+ xch->xch_cmd = cmd;
+ xch->xch_current_seq = NULL;
+ xch->xch_left_data_size = 0;
+ xch->xch_sequence_no = 0;
+ xch->xch_start_time = ddi_get_lbolt();
+ xch->xch_rxid = 0xFFFF;
+ xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
+ if (xch->xch_oxid == 0xFFFF) {
+ xch->xch_oxid =
+ atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
+ }
+
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+
+ (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
+ xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
+ bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
+ frm->frm_payload_size);
+ FFM_R_CTL(0x22, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x22;
+ FFM_TYPE(0x01, frm);
+ FFM_F_CTL(0x290000, frm);
+ FFM_OXID(xch->xch_oxid, frm);
+ FFM_RXID(xch->xch_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
+
+static fct_status_t
+fcoet_send_sol_ct(fct_cmd_t *cmd)
+{
+ fcoe_frame_t *frm;
+ fcoet_exchange_t *xch;
+
+ xch = CMD2XCH(cmd);
+ xch->xch_flags = 0;
+ xch->xch_ss = CMD2SS(cmd);
+ xch->xch_cmd = cmd;
+ xch->xch_current_seq = NULL;
+ xch->xch_left_data_size = 0;
+ xch->xch_sequence_no = 0;
+ xch->xch_start_time = ddi_get_lbolt();
+ xch->xch_rxid = 0xFFFF;
+ xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
+ if (xch->xch_oxid == 0xFFFF) {
+ xch->xch_oxid =
+ atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
+ }
+
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+
+ (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
+ (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
+ xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
+ bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
+ frm->frm_payload_size);
+ FFM_R_CTL(0x2, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x2;
+ FFM_TYPE(0x20, frm);
+ FFM_F_CTL(0x290000, frm);
+ FFM_OXID(xch->xch_oxid, frm);
+ FFM_RXID(xch->xch_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
+
+fct_status_t
+fcoet_send_status(fct_cmd_t *cmd)
+{
+ fcoe_frame_t *frm;
+ scsi_task_t *task = CMD2TASK(cmd);
+ fcoe_fcp_rsp_t *ffr;
+ int raw_frame_size;
+
+ /*
+ * Fast channel for good status phase
+ */
+ if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) {
+ return (fcoet_send_good_status(cmd));
+ }
+
+ raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
+ if (task->task_scsi_status == STATUS_CHECK) {
+ raw_frame_size += task->task_sense_length;
+ }
+ raw_frame_size = P2ROUNDUP(raw_frame_size, 4);
+
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ raw_frame_size, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ /*
+ * lock the xchg to avoid being released (by abort)
+ * after sent out and before release
+ */
+ FCOET_BUSY_XCHG(CMD2XCH(cmd));
+ }
+
+ /*
+ * If there's sense data, copy it first
+ */
+ if ((task->task_scsi_status == STATUS_CHECK) &&
+ task->task_sense_length) {
+ bcopy(task->task_sense_data, frm->frm_payload +
+ sizeof (fcoe_fcp_rsp_t), task->task_sense_length);
+ }
+
+ /*
+ * Fill fcp_rsp
+ */
+ ffr = (fcoe_fcp_rsp_t *)frm->frm_payload;
+ FCOE_V2B_4(0, ffr->ffr_retry_delay_timer);
+ FCOE_V2B_1(0, ffr->ffr_flags);
+ if (task->task_scsi_status == STATUS_CHECK || task->task_resid) {
+ if (task->task_scsi_status == STATUS_CHECK) {
+ ffr->ffr_flags[0] |= BIT_1;
+ }
+ if (task->task_status_ctrl == TASK_SCTRL_OVER) {
+ ffr->ffr_flags[0] |= BIT_2;
+ } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
+ ffr->ffr_flags[0] |= BIT_3;
+ }
+ }
+ FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status);
+ FCOE_V2B_4(task->task_resid, ffr->ffr_resid);
+ FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len);
+ FCOE_V2B_4(0, ffr->ffr_rsp_len);
+
+ /*
+ * Fill fc frame header
+ */
+ FFM_R_CTL(0x07, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x07;
+ FFM_TYPE(0x08, frm);
+ FFM_F_CTL(0x990000, frm);
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ FFM_SEQ_ID(0x01, frm);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
+
+static fct_status_t
+fcoet_send_els_response(fct_cmd_t *cmd)
+{
+ fcoe_frame_t *frm;
+
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ /*
+ * lock the xchg to avoid being released (by abort)
+ * after sent out and before release
+ */
+ FCOET_BUSY_XCHG(CMD2XCH(cmd));
+ }
+
+ bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload,
+ frm->frm_payload_size);
+ FFM_R_CTL(0x23, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x23;
+ FFM_TYPE(0x01, frm);
+ FFM_F_CTL(0x980000, frm);
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
+
+/* ARGSUSED */
+static fct_status_t
+fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags)
+{
+ fcoe_frame_t *frm;
+ fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
+
+ /*
+ * The relevant fcoet_exchange has been released
+ */
+ cmd->cmd_fca_private = NULL;
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ 12 + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, NULL);
+ }
+
+ bcopy(abts->abts_resp_payload, frm->frm_payload,
+ frm->frm_payload_size);
+ FFM_R_CTL(abts->abts_resp_rctl, frm);
+ FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl;
+ FFM_TYPE(0x00, frm);
+ FFM_F_CTL(0x980000, frm);
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
+
+/*
+ * enable/disable port is simple compared to physical FC HBAs
+ */
+fct_status_t
+fcoet_enable_port(fcoet_soft_state_t *ss)
+{
+ FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss);
+ /* Call fcoe function to online the port */
+ if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) ==
+ FCOE_FAILURE) {
+ return (FCT_FAILURE);
+ }
+
+ if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) {
+ atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED);
+ }
+
+ return (FCT_SUCCESS);
+}
+
+fct_status_t
+fcoet_disable_port(fcoet_soft_state_t *ss)
+{
+ fct_status_t status;
+
+ FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss);
+ /* Call fcoe function to offline the port */
+ status = fcoet_logo_fabric(ss);
+ ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
+ atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED);
+ return (status);
+}
+
+static fct_status_t
+fcoet_logo_fabric(fcoet_soft_state_t *ss)
+{
+ fcoe_frame_t *frm;
+ uint32_t req_payload_size = 16;
+ uint16_t xch_oxid, xch_rxid = 0xFFFF;
+
+ frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
+ req_payload_size + FCFH_SIZE, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, NULL);
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ }
+ xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
+ if (xch_oxid == 0xFFFF) {
+ xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
+ }
+ FFM_R_CTL(0x22, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x22;
+ FFM_TYPE(0x01, frm);
+ FFM_F_CTL(0x290000, frm);
+ FFM_OXID(xch_oxid, frm);
+ FFM_RXID(xch_rxid, frm);
+ FFM_S_ID(ss->ss_link_info.portid, frm);
+ FFM_D_ID(0xfffffe, frm);
+
+ FCOE_V2B_1(0x5, frm->frm_payload);
+ FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5);
+ bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8);
+ ss->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+
+}
+
+/*
+ * Called by: fcoet_register_remote_port
+ */
+/* ARGSUSED */
+static fct_status_t
+fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
+ fct_cmd_t *login)
+{
+ uint8_t *p;
+
+ p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
+ p[0] = ELS_OP_PLOGI;
+ p[4] = 0x20;
+ p[5] = 0x20;
+ p[7] = 3;
+ p[8] = 0x88;
+ p[10] = 8;
+ p[13] = 0xff; p[15] = 0x1f;
+ p[18] = 7; p[19] = 0xd0;
+
+ bcopy(port->port_pwwn, p + 20, 8);
+ bcopy(port->port_nwwn, p + 28, 8);
+
+ p[68] = 0x80;
+ p[74] = 8;
+ p[77] = 0xff;
+ p[81] = 1;
+
+ return (FCT_SUCCESS);
+}
+
+/*
+ * Called by: fcoet_register_remote_port
+ */
+/* ARGSUSED */
+static fct_status_t
+fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
+ fct_cmd_t *login)
+{
+ uint8_t *p;
+ /*
+ * ACC
+ */
+ p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
+ p[0] = ELS_OP_ACC;
+ p[4] = 0x20;
+ p[5] = 0x20;
+ p[7] = 0x0A;
+ p[10] = 0x05;
+ p[11] = 0xAC;
+
+ bcopy(port->port_pwwn, p + 20, 8);
+ bcopy(port->port_nwwn, p + 28, 8);
+
+ p[68] = 0x88;
+ return (FCT_SUCCESS);
+}
+
+static fct_status_t
+fcoet_send_good_status(fct_cmd_t *cmd)
+{
+ fcoe_frame_t *frm;
+ int raw_frame_size;
+
+ raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
+ frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
+ raw_frame_size, NULL);
+ if (frm == NULL) {
+ ASSERT(0);
+ return (FCT_FAILURE);
+ } else {
+ fcoet_init_tfm(frm, CMD2XCH(cmd));
+ bzero(frm->frm_payload, frm->frm_payload_size);
+ /*
+ * lock the xchg to avoid being released (by abort)
+ * after sent out and before release
+ */
+ FCOET_BUSY_XCHG(CMD2XCH(cmd));
+ }
+
+ /*
+ * Fill fc frame header
+ */
+ FFM_R_CTL(0x07, frm);
+ FRM2TFM(frm)->tfm_rctl = 0x07;
+ FFM_TYPE(0x08, frm);
+ FFM_F_CTL(0x990000, frm);
+ FFM_OXID(cmd->cmd_oxid, frm);
+ FFM_RXID(cmd->cmd_rxid, frm);
+ FFM_S_ID(cmd->cmd_lportid, frm);
+ FFM_D_ID(cmd->cmd_rportid, frm);
+ FFM_SEQ_ID(0x01, frm);
+
+ CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
+
+ return (FCT_SUCCESS);
+}
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h
new file mode 100644
index 0000000000..163d9ba9ac
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.h
@@ -0,0 +1,65 @@
+/*
+ * 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 _FCOET_FC_H
+#define _FCOET_FC_H
+
+#include <sys/stmf_defines.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+fct_status_t
+fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li);
+fct_status_t fcoet_register_remote_port(fct_local_port_t *port,
+ fct_remote_port_t *rp, fct_cmd_t *login);
+fct_status_t
+fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp);
+fct_status_t fcoet_send_cmd(fct_cmd_t *cmd);
+fct_status_t fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
+fct_status_t
+fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags);
+fct_status_t
+fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags);
+fct_status_t
+fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx);
+void fcoet_send_sol_flogi(fcoet_soft_state_t *ss);
+void fcoet_send_sol_abts(fcoet_exchange_t *xch);
+void fcoet_ctl(struct fct_local_port *port, int cmd, void *arg);
+void fcoet_populate_hba_fru_details(struct fct_local_port *port,
+ struct fct_port_attrs *port_attrs);
+fct_status_t fcoet_enable_port(fcoet_soft_state_t *ss);
+fct_status_t fcoet_disable_port(fcoet_soft_state_t *ss);
+fcoet_exchange_t *fcoet_init_sol_exchange(fct_cmd_t *cmd);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOET_FC_H */
diff --git a/usr/src/uts/common/io/comstar/port/fct/discovery.c b/usr/src/uts/common/io/comstar/port/fct/discovery.c
index 80116f8866..9db1776f39 100644
--- a/usr/src/uts/common/io/comstar/port/fct/discovery.c
+++ b/usr/src/uts/common/io/comstar/port/fct/discovery.c
@@ -218,14 +218,18 @@ fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed)
(void) strcpy(topology, topologies[li->port_topology]);
}
- if ((s == 0) || ((s & 0xf0) != 0) || ((s & (s - 1)) != 0)) {
+ if ((s == 0) || ((s & 0xf00) != 0) || ((s & (s - 1)) != 0)) {
speed[0] = '?';
+ } else if (s == PORT_SPEED_10G) {
+ speed[0] = '1';
+ speed[1] = '0';
+ speed[2] = 'G';
+ speed[3] = 0;
} else {
speed[0] = '0' + li->port_speed;
+ speed[1] = 'G';
+ speed[2] = 0;
}
-
- speed[1] = 'G';
- speed[2] = 0;
}
/*
diff --git a/usr/src/uts/common/io/comstar/port/fct/fct.c b/usr/src/uts/common/io/comstar/port/fct/fct.c
index a5c2e57395..0bc0285a0d 100644
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c
+++ b/usr/src/uts/common/io/comstar/port/fct/fct.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.
*/
@@ -479,6 +479,8 @@ fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn,
port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT;
if (attr->supported_speed & PORT_SPEED_8G)
port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT;
+ if (attr->supported_speed & PORT_SPEED_10G)
+ port_attr->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT;
switch (iport->iport_link_info.port_speed) {
case PORT_SPEED_1G:
port_attr->PortSpeed = FC_HBA_PORTSPEED_1GBIT;
@@ -492,6 +494,9 @@ fct_get_adapter_port_attr(fct_i_local_port_t *ilport, uint8_t *pwwn,
case PORT_SPEED_8G:
port_attr->PortSpeed = FC_HBA_PORTSPEED_8GBIT;
break;
+ case PORT_SPEED_10G:
+ port_attr->PortSpeed = FC_HBA_PORTSPEED_10GBIT;
+ break;
default:
port_attr->PortSpeed = FC_HBA_PORTSPEED_UNKNOWN;
break;
diff --git a/usr/src/uts/common/io/comstar/stmf/stmf.c b/usr/src/uts/common/io/comstar/stmf/stmf.c
index 83b4943bbd..685c9b1194 100644
--- a/usr/src/uts/common/io/comstar/stmf/stmf.c
+++ b/usr/src/uts/common/io/comstar/stmf/stmf.c
@@ -1341,8 +1341,21 @@ stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags)
if (sh == NULL)
return (NULL);
- sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
- sh->cp = GET_BYTE_OFFSET(sh->fp, stmf_sizes[struct_id].fw_private);
+ /*
+ * In principle, the implementation inside stmf_alloc should not
+ * be changed anyway. But the original order of framework private
+ * data and caller private data does not support sglist in the caller
+ * private data.
+ * To work around this, the memory segments of framework private
+ * data and caller private data are re-ordered here.
+ * A better solution is to provide a specific interface to allocate
+ * the sglist, then we will not need this workaround any more.
+ * But before the new interface is available, the memory segment
+ * ordering should be kept as is.
+ */
+ sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared);
+ sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh,
+ stmf_sizes[struct_id].shared + additional_size);
sh->fp->bp = sh;
/* Just store the total size instead of storing additional size */
diff --git a/usr/src/uts/common/io/fcoe/fcoe.c b/usr/src/uts/common/io/fcoe/fcoe.c
new file mode 100644
index 0000000000..e2dbe02921
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe.c
@@ -0,0 +1,1286 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Common FCoE interface interacts with MAC and FCoE clients, managing
+ * FCoE ports, doing MAC address discovery/managment, and FC frame
+ * encapsulation/decapsulation
+ */
+
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/cred.h>
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/byteorder.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/crc32.h>
+#include <sys/strsubr.h>
+
+#include <sys/mac_client.h>
+
+/*
+ * FCoE header files
+ */
+#include <sys/fcoe/fcoeio.h>
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoe.h>
+#include <fcoe_fc.h>
+#include <fcoe_eth.h>
+
+/*
+ * Function forward declaration
+ */
+static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
+ ddi_ctl_enum_t op, void *arg, void *result);
+static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp);
+static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp);
+static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+ cred_t *credp, int *rval);
+static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio,
+ void **ibuf, void **abuf, void **obuf);
+static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio,
+ void *obuf);
+static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode);
+static int fcoe_attach_init(fcoe_soft_state_t *this_ss);
+static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss);
+static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip);
+static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip);
+static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac,
+ int is_pwwn, uint8_t idx);
+static fcoe_mac_t *fcoe_create_mac_by_name(uint8_t *name);
+static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac);
+static void fcoe_watchdog(void *arg);
+static void fcoe_worker_init();
+static int fcoe_worker_fini();
+static void fcoe_worker_frame();
+static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count);
+
+/*
+ * Driver identificaton stuff
+ */
+static struct cb_ops fcoe_cb_ops = {
+ fcoe_open,
+ fcoe_close,
+ nodev,
+ nodev,
+ nodev,
+ nodev,
+ nodev,
+ fcoe_ioctl,
+ nodev,
+ nodev,
+ nodev,
+ nochpoll,
+ ddi_prop_op,
+ 0,
+ D_MP | D_NEW | D_HOTPLUG,
+ CB_REV,
+ nodev,
+ nodev
+};
+
+static struct bus_ops fcoe_busops = {
+ BUSO_REV,
+ nullbusmap, /* bus_map */
+ NULL, /* bus_get_intrspec */
+ NULL, /* bus_add_intrspec */
+ NULL, /* bus_remove_intrspec */
+ i_ddi_map_fault, /* bus_map_fault */
+ ddi_dma_map, /* bus_dma_map */
+ ddi_dma_allochdl, /* bus_dma_allochdl */
+ ddi_dma_freehdl, /* bus_dma_freehdl */
+ ddi_dma_bindhdl, /* bus_dma_bindhdl */
+ ddi_dma_unbindhdl, /* bus_unbindhdl */
+ ddi_dma_flush, /* bus_dma_flush */
+ ddi_dma_win, /* bus_dma_win */
+ ddi_dma_mctl, /* bus_dma_ctl */
+ fcoe_bus_ctl, /* bus_ctl */
+ ddi_bus_prop_op, /* bus_prop_op */
+ NULL, /* bus_get_eventcookie */
+ NULL, /* bus_add_eventcall */
+ NULL, /* bus_remove_event */
+ NULL, /* bus_post_event */
+ NULL, /* bus_intr_ctl */
+ NULL, /* bus_config */
+ NULL, /* bus_unconfig */
+ NULL, /* bus_fm_init */
+ NULL, /* bus_fm_fini */
+ NULL, /* bus_fm_access_enter */
+ NULL, /* bus_fm_access_exit */
+ NULL, /* bus_power */
+ NULL
+};
+
+static struct dev_ops fcoe_ops = {
+ DEVO_REV,
+ 0,
+ nodev,
+ nulldev,
+ nulldev,
+ fcoe_attach,
+ fcoe_detach,
+ nodev,
+ &fcoe_cb_ops,
+ &fcoe_busops,
+ ddi_power
+};
+
+#define FCOE_VERSION "20090311-1.00"
+#define FCOE_NAME "FCoE Transport v" FCOE_VERSION
+#define TASKQ_NAME_LEN 32
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ FCOE_NAME,
+ &fcoe_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, &modldrv, NULL
+};
+
+/*
+ * TRACE for all FCoE related modules
+ */
+static kmutex_t fcoe_trace_buf_lock;
+static int fcoe_trace_buf_curndx = 0;
+static int fcoe_trace_on = 1;
+static caddr_t fcoe_trace_buf = NULL;
+static clock_t fcoe_trace_start = 0;
+static caddr_t ftb = NULL;
+static int fcoe_trace_buf_size = (1 * 1024 * 1024);
+
+/*
+ * Driver's global variables
+ */
+static void *fcoe_state = NULL;
+fcoe_soft_state_t *fcoe_global_ss = NULL;
+int fcoe_use_ext_log = 1;
+
+static ddi_taskq_t *fcoe_worker_taskq;
+static fcoe_worker_t *fcoe_workers;
+static uint32_t fcoe_nworkers_running;
+
+const char *fcoe_workers_num = "workers-number";
+volatile int fcoe_nworkers;
+
+/*
+ * Common loadable module entry points _init, _fini, _info
+ */
+
+int
+_init(void)
+{
+ int ret;
+
+ ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0);
+ if (ret == 0) {
+ ret = mod_install(&modlinkage);
+ if (ret != 0) {
+ ddi_soft_state_fini(&fcoe_state);
+ } else {
+ fcoe_trace_start = ddi_get_lbolt();
+ ftb = kmem_zalloc(fcoe_trace_buf_size,
+ KM_SLEEP);
+ fcoe_trace_buf = ftb;
+ mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0);
+ }
+ }
+
+ FCOE_LOG("fcoe", "exit _init with %x", ret);
+
+ return (ret);
+}
+
+int
+_fini(void)
+{
+ int ret;
+
+ ret = mod_remove(&modlinkage);
+ if (ret == 0) {
+ ddi_soft_state_fini(&fcoe_state);
+ }
+
+ FCOE_LOG("fcoe", "exit _fini with %x", ret);
+ if (ret == 0) {
+ kmem_free(fcoe_trace_buf, fcoe_trace_buf_size);
+ mutex_destroy(&fcoe_trace_buf_lock);
+ }
+
+ return (ret);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * Autoconfiguration entry points: attach, detach, getinfo
+ */
+
+static int
+fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int ret = DDI_FAILURE;
+ int fcoe_ret;
+ int instance;
+ fcoe_soft_state_t *ss;
+
+ instance = ddi_get_instance(dip);
+ switch (cmd) {
+ case DDI_ATTACH:
+ ret = ddi_soft_state_zalloc(fcoe_state, instance);
+ if (ret == DDI_FAILURE) {
+ FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance);
+ return (ret);
+ }
+
+ ss = ddi_get_soft_state(fcoe_state, instance);
+ ss->ss_dip = dip;
+
+ ASSERT(fcoe_global_ss == NULL);
+ fcoe_global_ss = ss;
+ fcoe_ret = fcoe_attach_init(ss);
+ if (fcoe_ret == FCOE_SUCCESS) {
+ ret = DDI_SUCCESS;
+ }
+
+ FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret);
+ break;
+
+ case DDI_RESUME:
+ ret = DDI_SUCCESS;
+ break;
+
+ default:
+ FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd);
+ break;
+ }
+
+ return (ret);
+}
+
+static int
+fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ int ret = DDI_FAILURE;
+ int fcoe_ret;
+ int instance;
+ fcoe_soft_state_t *ss;
+
+ instance = ddi_get_instance(dip);
+ ss = ddi_get_soft_state(fcoe_state, instance);
+ if (ss == NULL) {
+ return (ret);
+ }
+
+ ASSERT(fcoe_global_ss != NULL);
+ ASSERT(dip == fcoe_global_ss->ss_dip);
+ switch (cmd) {
+ case DDI_DETACH:
+ fcoe_ret = fcoe_detach_uninit(ss);
+ if (fcoe_ret == FCOE_SUCCESS) {
+ ret = DDI_SUCCESS;
+ fcoe_global_ss = NULL;
+ }
+
+ break;
+
+ case DDI_SUSPEND:
+ ret = DDI_SUCCESS;
+ break;
+
+ default:
+ FCOE_LOG(0, "unsupported detach cmd-%x", cmd);
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * FCA driver's intercepted bus control operations.
+ */
+static int
+fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip,
+ ddi_ctl_enum_t op, void *clientarg, void *result)
+{
+ int ret;
+ switch (op) {
+ case DDI_CTLOPS_REPORTDEV:
+ case DDI_CTLOPS_IOMIN:
+ ret = DDI_SUCCESS;
+ break;
+
+ case DDI_CTLOPS_INITCHILD:
+ ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg);
+ break;
+
+ case DDI_CTLOPS_UNINITCHILD:
+ ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg);
+ break;
+
+ default:
+ ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result);
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * We need specify the dev address for client driver's instance, or we
+ * can't online client driver's instance.
+ */
+/* ARGSUSED */
+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++;
+ }
+
+ bzero(name, 32);
+ (void) sprintf((char *)name, "%x,0", *counter);
+ ddi_set_name_addr(client_dip, name);
+
+ return (DDI_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
+{
+ ddi_set_name_addr(client_dip, NULL);
+ return (DDI_SUCCESS);
+}
+
+/*
+ * Device access entry points
+ */
+static int
+fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp)
+{
+ int instance;
+ fcoe_soft_state_t *ss;
+
+ if (otype != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ /*
+ * Since this is for debugging only, only allow root to issue ioctl now
+ */
+ if (drv_priv(credp) != 0) {
+ return (EPERM);
+ }
+
+ instance = (int)getminor(*devp);
+ ss = ddi_get_soft_state(fcoe_state, instance);
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
+ /*
+ * It is already open for exclusive access.
+ * So shut the door on this caller.
+ */
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (EBUSY);
+ }
+
+ if (flag & FEXCL) {
+ if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) {
+ /*
+ * Exclusive operation not possible
+ * as it is already opened
+ */
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (EBUSY);
+ }
+ ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL;
+ }
+
+ ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN;
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+fcoe_close(dev_t dev, int flag, int otype, cred_t *credp)
+{
+ int instance;
+ fcoe_soft_state_t *ss;
+
+ if (otype != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ instance = (int)getminor(dev);
+ ss = ddi_get_soft_state(fcoe_state, instance);
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (ENODEV);
+ }
+
+ ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK;
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+ cred_t *credp, int *rval)
+{
+ fcoe_soft_state_t *ss;
+ int ret = 0;
+
+ if (drv_priv(credp) != 0) {
+ return (EPERM);
+ }
+
+ ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev));
+ if (ss == NULL) {
+ return (ENXIO);
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ return (ENXIO);
+ }
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ switch (cmd) {
+ case FCOEIO_CMD:
+ ret = fcoe_iocmd(ss, data, mode);
+ break;
+ default:
+ FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd);
+ ret = ENOTTY;
+ break;
+ }
+
+ return (ret);
+}
+
+static int
+fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio,
+ void **ibuf, void **abuf, void **obuf)
+{
+ int ret = 0;
+
+ *ibuf = NULL;
+ *abuf = NULL;
+ *obuf = NULL;
+ *fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP);
+ if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) {
+ ret = EFAULT;
+ goto copyin_iocdata_fail;
+ }
+
+ if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN ||
+ (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN ||
+ (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) {
+ ret = EFAULT;
+ goto copyin_iocdata_fail;
+ }
+
+ if ((*fcoeio)->fcoeio_ilen) {
+ *ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP);
+ if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf,
+ *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) {
+ ret = EFAULT;
+ goto copyin_iocdata_fail;
+ }
+ }
+
+ if ((*fcoeio)->fcoeio_alen) {
+ *abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP);
+ if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf,
+ *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) {
+ ret = EFAULT;
+ goto copyin_iocdata_fail;
+ }
+ }
+
+ if ((*fcoeio)->fcoeio_olen) {
+ *obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP);
+ }
+ return (ret);
+
+copyin_iocdata_fail:
+ if (*abuf) {
+ kmem_free(*abuf, (*fcoeio)->fcoeio_alen);
+ *abuf = NULL;
+ }
+
+ if (*ibuf) {
+ kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen);
+ *ibuf = NULL;
+ }
+
+ kmem_free(*fcoeio, sizeof (fcoeio_t));
+ return (ret);
+}
+
+static int
+fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf)
+{
+ if (fcoeio->fcoeio_olen) {
+ if (ddi_copyout(obuf,
+ (void *)(unsigned long)fcoeio->fcoeio_obuf,
+ fcoeio->fcoeio_olen, mode) != 0) {
+ return (EFAULT);
+ }
+ }
+
+ if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) {
+ return (EFAULT);
+ }
+ return (0);
+}
+
+static int
+fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode)
+{
+ int ret;
+ fcoe_mac_t *fcoe_mac;
+ void *ibuf = NULL;
+ void *obuf = NULL;
+ void *abuf = NULL;
+ fcoeio_t *fcoeio;
+
+ ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf);
+ if (ret != 0) {
+ goto fcoeiocmd_release_buf;
+ }
+
+ /*
+ * If an exclusive open was demanded during open, ensure that
+ * only one thread can execute an ioctl at a time
+ */
+ mutex_enter(&ss->ss_ioctl_mutex);
+ if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
+ if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ fcoeio->fcoeio_status = FCOEIOE_BUSY;
+ ret = EBUSY;
+ goto fcoeiocmd_release_buf;
+ }
+ ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY;
+ }
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ fcoeio->fcoeio_status = 0;
+
+ switch (fcoeio->fcoeio_cmd) {
+ case FCOEIO_CREATE_FCOE_PORT: {
+ fcoeio_create_port_param_t *param =
+ (fcoeio_create_port_param_t *)ibuf;
+ int cmpwwn = 0;
+ fcoe_port_t *eport;
+
+ if (fcoeio->fcoeio_ilen !=
+ sizeof (fcoeio_create_port_param_t) ||
+ fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) {
+ fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
+ ret = EINVAL;
+ break;
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ fcoe_mac = fcoe_create_mac_by_name(param->fcp_mac_name);
+ if (fcoe_mac == NULL) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC;
+ ret = EIO;
+ break;
+ }
+
+ if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) {
+ mutex_exit(&ss->ss_ioctl_mutex);
+ fcoeio->fcoeio_status = FCOEIOE_ALREADY;
+ ret = EALREADY;
+ break;
+ } else {
+ ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc,
+ &fcoeio->fcoeio_status);
+ if (ret != 0) {
+ fcoe_destroy_mac(fcoe_mac);
+ mutex_exit(&ss->ss_ioctl_mutex);
+ if (fcoeio->fcoeio_status == 0) {
+ fcoeio->fcoeio_status =
+ FCOEIOE_OPEN_MAC;
+ }
+ ret = EIO;
+ break;
+ } else {
+ fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED;
+ }
+ }
+
+ /*
+ * Provide PWWN and NWWN based on mac address
+ */
+ eport = &fcoe_mac->fm_eport;
+ if (!param->fcp_pwwn_provided) {
+ fcoe_init_wwn_from_mac(eport->eport_portwwn,
+ fcoe_mac->fm_current_addr, 1, 0);
+ } else {
+ (void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8);
+ }
+
+ if (!param->fcp_nwwn_provided) {
+ fcoe_init_wwn_from_mac(eport->eport_nodewwn,
+ fcoe_mac->fm_current_addr, 0, 0);
+ } else {
+ (void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8);
+ }
+
+ cmpwwn = fcoe_cmp_wwn(fcoe_mac);
+
+ if (cmpwwn != 0) {
+ if (cmpwwn == 1) {
+ fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED;
+ } else if (cmpwwn == -1) {
+ fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED;
+ }
+ (void) fcoe_close_mac(fcoe_mac);
+ fcoe_destroy_mac(fcoe_mac);
+ mutex_exit(&ss->ss_ioctl_mutex);
+ ret = ENOTUNIQ;
+ break;
+ }
+
+ if (ret == 0) {
+ ret = fcoe_create_port(ss->ss_dip,
+ fcoe_mac,
+ (param->fcp_port_type == FCOE_CLIENT_TARGET));
+ if (ret != 0) {
+ (void) fcoe_close_mac(fcoe_mac);
+ fcoe_destroy_mac(fcoe_mac);
+ fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT;
+ ret = EIO;
+ }
+ }
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ break;
+ }
+
+ case FCOEIO_DELETE_FCOE_PORT: {
+ uint8_t *mac_name = (uint8_t *)ibuf;
+
+ if (fcoeio->fcoeio_ilen > FCOE_MAX_MAC_NAME_LEN ||
+ fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) {
+ fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
+ ret = EINVAL;
+ break;
+ }
+
+ mutex_enter(&ss->ss_ioctl_mutex);
+ ret = fcoe_delete_port(ss->ss_dip, fcoeio, mac_name);
+ if (ret != 0) {
+ FCOE_LOG("fcoe",
+ "fcoe_delete_port failed: %d", ret);
+ }
+ mutex_exit(&ss->ss_ioctl_mutex);
+ break;
+ }
+
+ case FCOEIO_GET_FCOE_PORT_LIST: {
+ fcoe_port_list_t *list = (fcoe_port_list_t *)obuf;
+ int count;
+
+ if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ ||
+ fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) {
+ fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
+ ret = EINVAL;
+ break;
+ }
+ mutex_enter(&ss->ss_ioctl_mutex);
+
+ list->numPorts = 1 + (fcoeio->fcoeio_olen -
+ sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t);
+
+ count = fcoe_get_port_list(list->ports, list->numPorts);
+
+ if (count > list->numPorts) {
+ fcoeio->fcoeio_status = FCOEIOE_MORE_DATA;
+ ret = ENOSPC;
+ }
+ list->numPorts = count;
+ mutex_exit(&ss->ss_ioctl_mutex);
+
+ break;
+
+ }
+
+ default:
+ return (ENOTTY);
+ }
+
+ FCOE_LOG("fcoe", "fcoe_ioctl returned %d, fcoeio_status = %d",
+ ret, fcoeio->fcoeio_status);
+
+fcoeiocmd_release_buf:
+ if (ret == 0) {
+ ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
+ } else if (fcoeio->fcoeio_status) {
+ (void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
+ }
+
+ if (obuf != NULL) {
+ kmem_free(obuf, fcoeio->fcoeio_olen);
+ obuf = NULL;
+ }
+ if (abuf != NULL) {
+ kmem_free(abuf, fcoeio->fcoeio_alen);
+ abuf = NULL;
+ }
+
+ if (ibuf != NULL) {
+ kmem_free(ibuf, fcoeio->fcoeio_ilen);
+ ibuf = NULL;
+ }
+ kmem_free(fcoeio, sizeof (fcoeio_t));
+
+ return (ret);
+}
+
+/*
+ * Finish final initialization
+ */
+static int
+fcoe_attach_init(fcoe_soft_state_t *ss)
+{
+ char taskq_name[TASKQ_NAME_LEN];
+
+ if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR,
+ ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) {
+ FCOE_LOG("FCOE", "ddi_create_minor_node failed");
+ return (FCOE_FAILURE);
+ }
+
+ /*
+ * watchdog responsible for release frame and dispatch events
+ */
+ (void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac");
+ taskq_name[TASKQ_NAME_LEN - 1] = 0;
+ if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
+ taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
+ return (FCOE_FAILURE);
+ }
+
+ ss->ss_ioctl_flags = 0;
+ mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL);
+ list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t),
+ offsetof(fcoe_mac_t, fm_ss_node));
+ list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t),
+ offsetof(fcoe_i_frame_t, fmi_pending_node));
+
+ mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
+ cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
+ ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG;
+ (void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
+ fcoe_watchdog, ss, DDI_SLEEP);
+ while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
+ delay(10);
+ }
+ fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
+ DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4);
+ if (fcoe_nworkers < 1) {
+ fcoe_nworkers = 4;
+ }
+ fcoe_worker_init();
+
+ ddi_report_dev(ss->ss_dip);
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * Finish final uninitialization
+ */
+static int
+fcoe_detach_uninit(fcoe_soft_state_t *ss)
+{
+ int ret;
+ if (!list_is_empty(&ss->ss_mac_list)) {
+ FCOE_LOG("fcoe", "ss_mac_list is not empty when detach");
+ return (FCOE_FAILURE);
+ }
+
+ if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Stop watchdog
+ */
+ if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ mutex_enter(&ss->ss_watch_mutex);
+ ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
+ cv_broadcast(&ss->ss_watch_cv);
+ mutex_exit(&ss->ss_watch_mutex);
+ while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+ delay(10);
+ }
+ }
+
+ ddi_taskq_destroy(ss->ss_watchdog_taskq);
+ mutex_destroy(&ss->ss_watch_mutex);
+ cv_destroy(&ss->ss_watch_cv);
+
+ ddi_remove_minor_node(ss->ss_dip, NULL);
+ mutex_destroy(&ss->ss_ioctl_mutex);
+ list_destroy(&ss->ss_mac_list);
+
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * Return mac instance if it exist, or else return NULL.
+ */
+fcoe_mac_t *
+fcoe_lookup_mac_by_name(uint8_t *name)
+{
+ fcoe_mac_t *mac = NULL;
+
+ ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex));
+ for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
+ mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
+ if (strcmp((char *)name, mac->fm_link_name)) {
+ continue;
+ }
+ return (mac);
+ }
+ return (NULL);
+}
+
+/*
+ * port wwn will start with 20:..., node wwn will start with 10:...
+ */
+static void
+fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx)
+{
+ ASSERT(wwn != NULL);
+ ASSERT(mac != NULL);
+ wwn[0] = (is_pwwn + 1) << 4;
+ wwn[1] = idx;
+ bcopy(mac, wwn + 2, ETHERADDRL);
+}
+
+/*
+ * Return fcoe_mac if it exists, otherwise create a new one
+ */
+static fcoe_mac_t *
+fcoe_create_mac_by_name(uint8_t *name)
+{
+ fcoe_mac_t *mac = NULL;
+ ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex));
+
+ mac = fcoe_lookup_mac_by_name(name);
+ if (mac != NULL) {
+ FCOE_LOG("fcoe", "fcoe_create_mac_by_name found one mac %s",
+ name);
+ return (mac);
+ }
+
+ mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP);
+ bcopy(name, mac->fm_link_name, strlen((char *)name) + 1);
+ mac->fm_flags = 0;
+ mac->fm_ss = fcoe_global_ss;
+ list_insert_tail(&mac->fm_ss->ss_mac_list, mac);
+ FCOE_LOG("fcoe", "fcoe_create_mac_by_name created one mac %s", name);
+ return (mac);
+}
+
+void
+fcoe_destroy_mac(fcoe_mac_t *mac)
+{
+ ASSERT(mac != NULL);
+ list_remove(&mac->fm_ss->ss_mac_list, mac);
+ kmem_free(mac, sizeof (fcoe_mac_t));
+}
+
+/*
+ * raw frame layout:
+ * ethernet header + vlan header (optional) + FCoE header +
+ * FC frame + FCoE tailer
+ */
+/* ARGSUSED */
+mblk_t *
+fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size)
+{
+ mblk_t *mp;
+ int err;
+
+ /*
+ * FCFH_SIZE + PADDING_SIZE
+ */
+ ASSERT(raw_frame_size >= 60);
+ while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) {
+ if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) {
+ FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err);
+ return (NULL);
+ }
+ }
+ mp->b_wptr = mp->b_rptr + raw_frame_size;
+
+ /*
+ * We should always zero FC frame header
+ */
+ bzero(mp->b_rptr + PADDING_HEADER_SIZE,
+ sizeof (fcoe_fc_frame_header_t));
+ return (mp);
+}
+
+static void
+fcoe_watchdog(void *arg)
+{
+ fcoe_soft_state_t *ss = (fcoe_soft_state_t *)arg;
+ fcoe_i_frame_t *fmi;
+ fcoe_mac_t *mac = NULL;
+
+ FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss);
+
+ mutex_enter(&ss->ss_watch_mutex);
+ ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
+ while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
+ while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) {
+ list_remove(&ss->ss_pfrm_list, fmi);
+ mutex_exit(&ss->ss_watch_mutex);
+
+ mac = EPORT2MAC(fmi->fmi_frame->frm_eport);
+ mac->fm_client.ect_release_sol_frame(fmi->fmi_frame);
+
+ mutex_enter(&ss->ss_watch_mutex);
+ mac->fm_frm_cnt--;
+ }
+
+ ss->ss_flags |= SS_FLAG_DOG_WAITING;
+ (void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex);
+ ss->ss_flags &= ~SS_FLAG_DOG_WAITING;
+ }
+
+ ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
+ mutex_exit(&ss->ss_watch_mutex);
+}
+
+static void
+fcoe_worker_init()
+{
+ uint32_t i;
+
+ fcoe_nworkers_running = 0;
+ fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ",
+ fcoe_nworkers, TASKQ_DEFAULTPRI, 0);
+ fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) *
+ fcoe_nworkers, KM_SLEEP);
+ for (i = 0; i < fcoe_nworkers; i++) {
+ fcoe_worker_t *w = &fcoe_workers[i];
+ mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
+ w->worker_flags &= ~FCOE_WORKER_TERMINATE;
+ list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t),
+ offsetof(fcoe_i_frame_t, fmi_pending_node));
+ (void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame,
+ w, DDI_SLEEP);
+ }
+ while (fcoe_nworkers_running != fcoe_nworkers) {
+ delay(10);
+ }
+}
+
+static int
+fcoe_worker_fini()
+{
+ uint32_t i;
+
+ for (i = 0; i < fcoe_nworkers; i++) {
+ fcoe_worker_t *w = &fcoe_workers[i];
+ mutex_enter(&w->worker_lock);
+ if (w->worker_flags & FCOE_WORKER_STARTED) {
+ w->worker_flags |= FCOE_WORKER_TERMINATE;
+ cv_signal(&w->worker_cv);
+ }
+ mutex_exit(&w->worker_lock);
+ }
+
+ while (fcoe_nworkers_running != 0) {
+ delay(drv_usectohz(10000));
+ }
+
+ ddi_taskq_destroy(fcoe_worker_taskq);
+ kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers);
+ fcoe_workers = NULL;
+ return (FCOE_SUCCESS);
+}
+
+static int
+fcoe_crc_verify(fcoe_frame_t *frm)
+{
+ uint32_t crc;
+ uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc;
+ uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) |
+ (crc_array[2] << 16) | (crc_array[3] << 24));
+ CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table);
+ return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE);
+}
+
+static void
+fcoe_worker_frame(void *arg)
+{
+ fcoe_worker_t *w = (fcoe_worker_t *)arg;
+ fcoe_i_frame_t *fmi;
+ int ret;
+
+ atomic_add_32(&fcoe_nworkers_running, 1);
+ mutex_enter(&w->worker_lock);
+ w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE;
+ while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) {
+ /*
+ * loop through the frames
+ */
+ while (fmi = list_head(&w->worker_frm_list)) {
+ list_remove(&w->worker_frm_list, fmi);
+ mutex_exit(&w->worker_lock);
+ /*
+ * do the checksum
+ */
+ ret = fcoe_crc_verify(fmi->fmi_frame);
+ if (ret == FCOE_SUCCESS) {
+ fmi->fmi_mac->fm_client.ect_rx_frame(
+ fmi->fmi_frame);
+ } else {
+ fcoe_release_frame(fmi->fmi_frame);
+ }
+ mutex_enter(&w->worker_lock);
+ w->worker_ntasks--;
+ }
+ w->worker_flags &= ~FCOE_WORKER_ACTIVE;
+ cv_wait(&w->worker_cv, &w->worker_lock);
+ w->worker_flags |= FCOE_WORKER_ACTIVE;
+ }
+ w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE);
+ mutex_exit(&w->worker_lock);
+ atomic_add_32(&fcoe_nworkers_running, -1);
+ list_destroy(&w->worker_frm_list);
+}
+
+void
+fcoe_post_frame(fcoe_frame_t *frm)
+{
+ fcoe_worker_t *w;
+ uint16_t oxid = FRM_OXID(frm);
+
+ w = &fcoe_workers[oxid % fcoe_nworkers_running];
+ mutex_enter(&w->worker_lock);
+ list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private);
+ w->worker_ntasks++;
+ if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) {
+ cv_signal(&w->worker_cv);
+ }
+ mutex_exit(&w->worker_lock);
+}
+
+/*
+ * The max length of every LOG is 158
+ */
+void
+fcoe_trace(caddr_t ident, const char *fmt, ...)
+{
+ va_list args;
+ char tbuf[160];
+ int len;
+ clock_t curclock;
+ clock_t usec;
+
+ if (fcoe_trace_on == 0) {
+ return;
+ }
+
+ curclock = ddi_get_lbolt();
+ usec = (curclock - fcoe_trace_start) * usec_per_tick;
+ len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec /
+ (1000 * 1000)), ((usec % (1000 * 1000)) / 1000),
+ curclock, (ident ? ident : "unknown"));
+ va_start(args, fmt);
+ len += vsnprintf(tbuf + len, 158 - len, fmt, args);
+ va_end(args);
+
+ if (len > 158) {
+ len = 158;
+ }
+ tbuf[len++] = '\n';
+ tbuf[len] = 0;
+
+ mutex_enter(&fcoe_trace_buf_lock);
+ bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1);
+ fcoe_trace_buf_curndx += len;
+ if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) {
+ fcoe_trace_buf_curndx = 0;
+ }
+ mutex_exit(&fcoe_trace_buf_lock);
+}
+
+/*
+ * Check whether the pwwn or nwwn already exist or not
+ * Return value:
+ * 1: PWWN conflicted
+ * -1: NWWN conflicted
+ * 0: No conflict
+ */
+static int
+fcoe_cmp_wwn(fcoe_mac_t *checkedmac)
+{
+ fcoe_mac_t *mac;
+ uint8_t *nwwn, *pwwn, *cnwwn, *cpwwn;
+
+ cnwwn = checkedmac->fm_eport.eport_nodewwn;
+ cpwwn = checkedmac->fm_eport.eport_portwwn;
+ ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex));
+
+ for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
+ mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
+ if (mac == checkedmac) {
+ continue;
+ }
+ nwwn = mac->fm_eport.eport_nodewwn;
+ pwwn = mac->fm_eport.eport_portwwn;
+
+ if (memcmp(nwwn, cnwwn, 8) == 0) {
+ return (-1);
+ }
+
+ if (memcmp(pwwn, cpwwn, 8) == 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+fcoe_get_port_list(fcoe_port_instance_t *ports, int count)
+{
+ fcoe_mac_t *mac = NULL;
+ int i = 0;
+
+ ASSERT(ports != NULL);
+ ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex));
+
+ for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
+ mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
+ if (i < count) {
+ bcopy(mac->fm_eport.eport_portwwn,
+ ports[i].fpi_pwwn, 8);
+ bcopy(mac->fm_link_name,
+ ports[i].fpi_mac_link_name, MAXLINKNAMELEN);
+ bcopy(mac->fm_current_addr,
+ ports[i].fpi_mac_current_addr, ETHERADDRL);
+ bcopy(mac->fm_primary_addr,
+ ports[i].fpi_mac_factory_addr, ETHERADDRL);
+ ports[i].fpi_port_type =
+ EPORT_CLT_TYPE(&mac->fm_eport);
+ ports[i].fpi_mtu_size =
+ mac->fm_eport.eport_mtu;
+ ports[i].fpi_mac_promisc =
+ mac->fm_promisc_handle != NULL ? 1 : 0;
+ }
+ i++;
+ }
+ return (i);
+}
diff --git a/usr/src/uts/common/io/fcoe/fcoe.conf b/usr/src/uts/common/io/fcoe/fcoe.conf
new file mode 100644
index 0000000000..d2a6aa25f8
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe.conf
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+#
+# fcoe is nexus driver with children
+#
+name="fcoe" parent="/";
+
+#
+# number of workers to handle crc check
+#
+#workers-number=4;
diff --git a/usr/src/uts/common/io/fcoe/fcoe.h b/usr/src/uts/common/io/fcoe/fcoe.h
new file mode 100644
index 0000000000..222a29bf12
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe.h
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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.
+ */
+#ifndef _FCOE_H_
+#define _FCOE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+extern int fcoe_use_ext_log;
+extern struct fcoe_soft_state *fcoe_global_ss;
+
+/*
+ * Caution: 1) LOG will be available in debug/non-debug mode
+ * 2) Anything which can potentially flood the log should be under
+ * extended logging, and use FCOE_EXT_LOG.
+ * 3) Don't use FCOE_EXT_LOG in performance-critical code path, such
+ * as normal SCSI I/O code path. It could hurt system performance.
+ * 4) Use kmdb to change foce_use_ext_log in the fly to adjust
+ * tracing
+ */
+#define FCOE_EXT_LOG(log_ident, ...) \
+ do { \
+ if (fcoe_use_ext_log) { \
+ fcoe_trace(log_ident, __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define FCOE_LOG(log_ident, ...) \
+ fcoe_trace(log_ident, __VA_ARGS__)
+
+/*
+ * There will be only one fcoe instance
+ */
+typedef struct fcoe_soft_state {
+ dev_info_t *ss_dip;
+ uint32_t ss_flags;
+ list_t ss_mac_list;
+ uint32_t ss_ioctl_flags;
+ kmutex_t ss_ioctl_mutex;
+
+ /*
+ * watchdog stuff
+ */
+ ddi_taskq_t *ss_watchdog_taskq;
+ kcondvar_t ss_watch_cv;
+ kmutex_t ss_watch_mutex;
+ list_t ss_pfrm_list; /* Pending frame */
+} fcoe_soft_state_t;
+
+#define SS_FLAG_TERMINATE_WATCHDOG 0x0020
+#define SS_FLAG_WATCHDOG_RUNNING 0x0040
+#define SS_FLAG_DOG_WAITING 0x0080
+
+/*
+ * Driver name
+ */
+#define FCOEI_DRIVER_NAME "fcoei"
+#define FCOET_DRIVER_NAME "fcoet"
+
+/*
+ * One for each ethernet port
+ */
+typedef struct fcoe_mac
+{
+ list_node_t fm_ss_node;
+ char fm_link_name[MAXLINKNAMELEN];
+ uint32_t fm_flags;
+
+ fcoe_soft_state_t *fm_ss;
+ fcoe_port_t fm_eport;
+ fcoe_client_t fm_client;
+ dev_info_t *fm_client_dev;
+
+ mac_handle_t fm_handle;
+ mac_client_handle_t fm_cli_handle;
+ mac_promisc_handle_t fm_promisc_handle;
+ mac_notify_handle_t fm_notify_handle;
+ mac_unicast_handle_t fm_unicst_handle;
+ uint8_t fm_primary_addr[ETHERADDRL];
+ uint8_t fm_current_addr[ETHERADDRL];
+ uint32_t fm_running:1,
+ fm_force_promisc:1,
+ fm_rsvd:18,
+ fm_state:4,
+ fm_link_state:8;
+ uint32_t fm_frm_cnt;
+ kcondvar_t fm_tx_cv;
+ kmutex_t fm_mutex;
+} fcoe_mac_t;
+
+#define FCOE_MAC_STATE_OFFLINE 0x0
+#define FCOE_MAC_STATE_ONLINE 0x1
+
+#define FCOE_MAC_LINK_STATE_DOWN 0x00
+#define FCOE_MAC_LINK_STATE_UP 0x01
+
+#define FCOE_MAC_FLAG_ENABLED 0x01
+#define FCOE_MAC_FLAG_BOUND 0x02
+
+typedef struct fcoe_frame_header {
+ uint8_t ffh_ver[1]; /* version field - upper 4 bits */
+ uint8_t ffh_resvd[12];
+ uint8_t ffh_sof[1]; /* start of frame per RFC 3643 */
+} fcoe_frame_header_t;
+
+typedef struct fcoe_frame_tailer {
+ uint8_t fft_crc[4]; /* FC packet CRC */
+ uint8_t fft_eof[1];
+ uint8_t fft_resvd[3];
+} fcoe_frame_tailer_t;
+
+/*
+ * RAW frame structure
+ * It is used to describe the content of every mblk
+ */
+typedef struct fcoe_i_frame {
+ list_node_t fmi_pending_node;
+
+ fcoe_frame_t *fmi_frame; /* to common struct */
+ fcoe_mac_t *fmi_mac; /* to/from where */
+
+ /*
+ * FRAME structure
+ */
+ struct ether_header *fmi_efh; /* 14 bytes eth header */
+ fcoe_frame_header_t *fmi_ffh; /* 14 bytes FCOE hader */
+ uint8_t *fmi_fc_frame;
+ fcoe_frame_tailer_t *fmi_fft; /* 8 bytes FCOE tailer */
+} fcoe_i_frame_t;
+
+typedef struct fcoe_worker {
+ list_t worker_frm_list;
+ kmutex_t worker_lock;
+ kcondvar_t worker_cv;
+ uint32_t worker_flags;
+ uint32_t worker_ntasks;
+} fcoe_worker_t;
+
+#define FCOE_WORKER_TERMINATE 0x01
+#define FCOE_WORKER_STARTED 0x02
+#define FCOE_WORKER_ACTIVE 0x04
+
+/*
+ * IOCTL supporting stuff
+ */
+#define FCOE_IOCTL_FLAG_MASK 0xFF
+#define FCOE_IOCTL_FLAG_IDLE 0x00
+#define FCOE_IOCTL_FLAG_OPEN 0x01
+#define FCOE_IOCTL_FLAG_EXCL 0x02
+#define FCOE_IOCTL_FLAG_EXCL_BUSY 0x04
+
+/*
+ * define common-used macros to simplify coding
+ */
+#define FCOE_FIP_TYPE 0x8914
+#define FCOE_802_1Q_TAG 0x8100
+
+#define PADDING_HEADER_SIZE (sizeof (struct ether_header) + \
+ sizeof (fcoe_frame_header_t))
+#define PADDING_SIZE (PADDING_HEADER_SIZE + sizeof (fcoe_frame_tailer_t))
+
+#define EPORT2MAC(x_eport) ((fcoe_mac_t *)(x_eport)->eport_fcoe_private)
+
+#define FRM2MAC(x_frm) (EPORT2MAC((x_frm)->frm_eport))
+#define FRM2FMI(x_frm) ((fcoe_i_frame_t *)(x_frm)->frm_fcoe_private)
+#define FRM2MBLK(x_frm) ((mblk_t *)(x_frm)->frm_netb)
+
+#define FCOE_VER 0
+#define FCOE_DECAPS_VER(x_ffh) ((x_ffh)->ffh_ver[0] >> 4)
+#define FCOE_ENCAPS_VER(x_ffh, x_v) \
+ { \
+ (x_ffh)->ffh_ver[0] = ((x_v) << 4); \
+ }
+
+/*
+ * fcoe driver common functions
+ */
+extern fcoe_mac_t *fcoe_lookup_mac_by_name(uint8_t *);
+extern void fcoe_destroy_mac(fcoe_mac_t *);
+extern mblk_t *fcoe_get_mblk(fcoe_mac_t *, uint32_t);
+extern void fcoe_post_frame(fcoe_frame_t *);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOE_H_ */
diff --git a/usr/src/uts/common/io/fcoe/fcoe_eth.c b/usr/src/uts/common/io/fcoe/fcoe_eth.c
new file mode 100644
index 0000000000..91b4aa2032
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe_eth.c
@@ -0,0 +1,373 @@
+/*
+ * 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/stat.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/inttypes.h>
+#include <sys/strsun.h>
+#include <sys/mac_client.h>
+
+/*
+ * FCoE header files
+ */
+#include <sys/fcoe/fcoeio.h>
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoe.h>
+#include <fcoe_eth.h>
+#include <fcoe_fc.h>
+
+static void fcoe_rx(void *arg, mac_resource_handle_t mrh,
+ mblk_t *mp, boolean_t loopback);
+static void fcoe_mac_notify(void *arg, mac_notify_type_t type);
+
+/*
+ * Global variable definitions
+ */
+
+/*
+ * Internal tunable, used to enable p2p mode
+ */
+volatile uint32_t fcoe_enable_p2pmode = 0;
+
+int
+fcoe_open_mac(fcoe_mac_t *mac, int force_promisc, fcoeio_stat_t *err_detail)
+{
+ int ret;
+ int fcoe_ret;
+ char cli_name[MAXNAMELEN];
+ mac_diag_t diag;
+ uint16_t fm_open_flag = 0;
+
+ *err_detail = 0;
+
+ /*
+ * Open MAC interface
+ */
+ ret = mac_open_by_linkname(mac->fm_link_name, &mac->fm_handle);
+ if (ret != 0) {
+ cmn_err(CE_WARN, "Open network interface %s failed",
+ mac->fm_link_name);
+ FCOE_LOG("fcoe", "mac_open_by_linkname %s failed %x",
+ mac->fm_link_name, ret);
+ return (FCOE_FAILURE);
+ }
+
+ if (mac_is_vnic(mac->fm_handle)) {
+ (void) mac_close(mac->fm_handle);
+ *err_detail = FCOEIOE_VNIC_UNSUPPORT;
+ return (FCOE_FAILURE);
+ }
+
+ (void) sprintf(cli_name, "%s-%s", mac->fm_link_name, "fcoe");
+
+ ret = mac_client_open(mac->fm_handle,
+ &mac->fm_cli_handle, cli_name, fm_open_flag);
+ if (ret != 0) {
+ (void) fcoe_close_mac(mac);
+ return (FCOE_FAILURE);
+ }
+ /*
+ * Cache the pointer of the immutable MAC inforamtion and
+ * the current and primary MAC address
+ */
+ mac_unicast_primary_get(mac->fm_handle, mac->fm_primary_addr);
+ bcopy(mac->fm_primary_addr, mac->fm_current_addr,
+ ETHERADDRL);
+
+ if (mac_unicast_add(mac->fm_cli_handle, NULL, MAC_UNICAST_PRIMARY,
+ &mac->fm_unicst_handle, 0, &diag)) {
+ (void) fcoe_close_mac(mac);
+ return (FCOE_FAILURE);
+ }
+
+ if (force_promisc) {
+ mac->fm_force_promisc = B_TRUE;
+ }
+
+ /* Get mtu */
+ mac_sdu_get(mac->fm_handle, NULL, &mac->fm_eport.eport_mtu);
+ if (mac->fm_eport.eport_mtu < FCOE_MIN_MTU_SIZE) {
+ if (!fcoe_enable_p2pmode || mac->fm_eport.eport_mtu < 1500) {
+ /*
+ * Fail open if fail to get mtu, or we are not
+ * using p2p, or we are using p2p, but
+ * the mtu is too small
+ */
+ (void) fcoe_close_mac(mac);
+ *err_detail = FCOEIOE_NEED_JUMBO_FRAME;
+ return (FCOE_FAILURE);
+ }
+ }
+
+ mac->fm_eport.eport_link_speed =
+ mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED);
+
+ cv_init(&mac->fm_tx_cv, NULL, CV_DRIVER, NULL);
+ mutex_init(&mac->fm_mutex, NULL, MUTEX_DRIVER, NULL);
+ mac->fm_running = B_TRUE;
+
+ fcoe_ret = FCOE_SUCCESS;
+ return (fcoe_ret);
+}
+
+int
+fcoe_close_mac(fcoe_mac_t *mac)
+{
+ int ret;
+
+ if (mac->fm_handle == NULL) {
+ return (FCOE_SUCCESS);
+ }
+
+ if (mac->fm_running) {
+ cv_destroy(&mac->fm_tx_cv);
+ mutex_destroy(&mac->fm_mutex);
+ mac->fm_running = B_FALSE;
+ }
+
+ if (mac->fm_promisc_handle != NULL) {
+ mac_promisc_remove(mac->fm_promisc_handle);
+ mac->fm_promisc_handle = NULL;
+ } else {
+ mac_rx_clear(mac->fm_cli_handle);
+ }
+
+ if (mac->fm_notify_handle != NULL) {
+ ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE);
+ ASSERT(ret == 0);
+ mac->fm_notify_handle = NULL;
+ }
+
+ if (mac->fm_unicst_handle != NULL) {
+ (void) mac_unicast_remove(mac->fm_cli_handle,
+ mac->fm_unicst_handle);
+ mac->fm_unicst_handle = NULL;
+ }
+
+ mac_client_close(mac->fm_cli_handle, 0);
+ mac->fm_cli_handle = NULL;
+
+ (void) mac_close(mac->fm_handle);
+ mac->fm_handle = NULL;
+
+ return (FCOE_SUCCESS);
+}
+
+int
+fcoe_enable_callback(fcoe_mac_t *mac)
+{
+ int ret;
+
+ /*
+ * Set message callback
+ */
+ if (mac->fm_force_promisc) {
+ ret = mac_promisc_add(mac->fm_cli_handle,
+ MAC_CLIENT_PROMISC_FILTERED, fcoe_rx, mac,
+ &mac->fm_promisc_handle,
+ MAC_PROMISC_FLAGS_NO_TX_LOOP);
+ if (ret != 0) {
+ cmn_err(CE_WARN, "Enable promisc mode on %s failed",
+ mac->fm_link_name);
+ FCOE_LOG("foce", "mac_promisc_add on %s failed %x",
+ mac->fm_link_name, ret);
+ return (FCOE_FAILURE);
+ }
+ } else {
+ mac_rx_set(mac->fm_cli_handle, fcoe_rx, mac);
+ }
+
+ /* Get the link state, if it's up, we will need to notify client */
+ mac->fm_link_state =
+ mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP)?
+ FCOE_MAC_LINK_STATE_UP:FCOE_MAC_LINK_STATE_DOWN;
+
+ /*
+ * Add a notify function so that we get updates from MAC
+ */
+ mac->fm_notify_handle = mac_notify_add(mac->fm_handle,
+ fcoe_mac_notify, (void *)mac);
+ return (FCOE_SUCCESS);
+}
+
+int
+fcoe_disable_callback(fcoe_mac_t *mac)
+{
+ int ret;
+
+ if (mac->fm_promisc_handle) {
+ mac_promisc_remove(mac->fm_promisc_handle);
+ mac->fm_promisc_handle = NULL;
+ } else {
+ mac_rx_clear(mac->fm_cli_handle);
+ }
+
+ if (mac->fm_notify_handle) {
+ ret = mac_notify_remove(mac->fm_notify_handle, B_TRUE);
+ ASSERT(ret == 0);
+ mac->fm_notify_handle = NULL;
+ }
+
+ ret = fcoe_mac_set_address(&mac->fm_eport,
+ mac->fm_primary_addr, B_FALSE);
+ FCOE_SET_DEFAULT_FPORT_ADDR(mac->fm_eport.eport_efh_dst);
+ return (ret);
+}
+
+/* ARGSUSED */
+static void
+fcoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback)
+{
+ fcoe_mac_t *mac = (fcoe_mac_t *)arg;
+ mblk_t *next;
+ fcoe_frame_t *frm;
+ uint32_t raw_frame_size, frame_size;
+ uint16_t frm_type;
+
+ while (mp != NULL) {
+ next = mp->b_next;
+ mp->b_next = NULL;
+ frm_type = ntohs(*(uint16_t *)((uintptr_t)mp->b_rptr + 12));
+
+ if (frm_type != ETHERTYPE_FCOE) {
+ /*
+ * This mp is not allocated in FCoE, but we must free it
+ */
+ freeb(mp);
+ mp = next;
+ continue;
+ }
+
+ raw_frame_size = MBLKL(mp);
+ frame_size = raw_frame_size - PADDING_SIZE;
+ frm = fcoe_allocate_frame(&mac->fm_eport, frame_size, mp);
+ if (frm != NULL) {
+ fcoe_post_frame(frm);
+ }
+
+ mp = next;
+ }
+}
+
+static void
+fcoe_mac_notify(void *arg, mac_notify_type_t type)
+{
+ fcoe_mac_t *mac = (fcoe_mac_t *)arg;
+
+ /*
+ * We assume that the calls to this notification callback are serialized
+ * by MAC layer
+ */
+
+ switch (type) {
+ case MAC_NOTE_LINK:
+ /*
+ * This notification is sent every time the MAC driver
+ * updates the link state.
+ */
+ if (mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP) != 0) {
+ if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP) {
+ break;
+ }
+ /* Get speed */
+ 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);
+
+ FCOE_SET_DEFAULT_FPORT_ADDR(
+ mac->fm_eport.eport_efh_dst);
+
+ mac->fm_link_state = FCOE_MAC_LINK_STATE_UP;
+ FCOE_LOG(mac->fm_link_name,
+ "fcoe_mac_notify: arg/%p LINK up", arg, type);
+ fcoe_mac_notify_link_up(mac);
+ } else {
+ if (mac->fm_link_state == FCOE_MAC_LINK_STATE_DOWN) {
+ break;
+ }
+ mac->fm_link_state = FCOE_MAC_LINK_STATE_DOWN;
+ FCOE_LOG(mac->fm_link_name,
+ "fcoe_mac_notify: arg/%p LINK down", arg, type);
+ fcoe_mac_notify_link_down(mac);
+ }
+ break;
+
+ case MAC_NOTE_TX:
+ /*
+ * MAC is not so busy now, then wake up fcoe_tx_frame to try
+ */
+ mutex_enter(&mac->fm_mutex);
+ cv_broadcast(&mac->fm_tx_cv);
+ mutex_exit(&mac->fm_mutex);
+
+ FCOE_LOG("fcoe_mac_notify", "wake up");
+ break;
+
+ default:
+ FCOE_LOG("fcoe_mac_notify", "not supported arg/%p, type/%d",
+ arg, type);
+ break;
+ }
+}
+
+int
+fcoe_mac_set_address(fcoe_port_t *eport, uint8_t *addr, boolean_t fc_assigned)
+{
+ fcoe_mac_t *mac = EPORT2MAC(eport);
+ int ret;
+
+ if (bcmp(addr, mac->fm_current_addr, 6) == 0) {
+ return (FCOE_SUCCESS);
+ }
+
+ mutex_enter(&mac->fm_mutex);
+ if (mac->fm_promisc_handle == NULL) {
+ ret = mac_unicast_primary_set(mac->fm_handle, addr);
+ if (ret != 0) {
+ mutex_exit(&mac->fm_mutex);
+ cmn_err(CE_WARN, "Set primary unicast address on %s "
+ "failed", mac->fm_link_name);
+ FCOE_LOG("fcoe", "mac_unicast_primary_set on %s "
+ "failed %x", mac->fm_link_name, ret);
+ return (FCOE_FAILURE);
+ }
+ }
+ if (fc_assigned) {
+ bcopy(addr, mac->fm_current_addr, ETHERADDRL);
+ } else {
+ bcopy(mac->fm_primary_addr,
+ mac->fm_current_addr, ETHERADDRL);
+ }
+ mutex_exit(&mac->fm_mutex);
+ return (FCOE_SUCCESS);
+}
diff --git a/usr/src/uts/common/io/fcoe/fcoe_eth.h b/usr/src/uts/common/io/fcoe/fcoe_eth.h
new file mode 100644
index 0000000000..eff72c1345
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe_eth.h
@@ -0,0 +1,45 @@
+/*
+ * 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 _FCOE_ETH_H_
+#define _FCOE_ETH_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+extern int fcoe_open_mac(fcoe_mac_t *, int, fcoeio_stat_t *);
+extern int fcoe_close_mac(fcoe_mac_t *);
+extern int fcoe_enable_callback(fcoe_mac_t *);
+extern int fcoe_disable_callback(fcoe_mac_t *);
+extern int fcoe_mac_set_address(fcoe_port_t *, uint8_t *, boolean_t);
+
+#endif /* _KERNEL */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOE_ETH_H_ */
diff --git a/usr/src/uts/common/io/fcoe/fcoe_fc.c b/usr/src/uts/common/io/fcoe/fcoe_fc.c
new file mode 100644
index 0000000000..e1cb5e3bad
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe_fc.c
@@ -0,0 +1,490 @@
+/*
+ * 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 its clients (FCoEI/FCoET)
+ */
+
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunndi.h>
+#include <sys/byteorder.h>
+#include <sys/atomic.h>
+#include <sys/sysmacros.h>
+#include <sys/cmn_err.h>
+#include <sys/crc32.h>
+#include <sys/fcntl.h>
+#include <sys/unistd.h>
+#include <sys/mac_client.h>
+
+/*
+ * FCoE header files
+ */
+#include <sys/fcoe/fcoeio.h>
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoe.h>
+#include <fcoe_fc.h>
+#include <fcoe_eth.h>
+
+static void fcoe_fill_frame_headers(fcoe_frame_t *frm);
+static void fcoe_fill_frame_tailers(fcoe_frame_t *frm);
+static void fcoe_deregister_client(fcoe_port_t *eport);
+static int fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg);
+static void fcoe_tx_frame(fcoe_frame_t *frm);
+static void *fcoe_alloc_netb(fcoe_port_t *eport,
+ uint32_t fc_frame_size, uint8_t **ppfc);
+static void fcoe_free_netb(void *netb);
+
+/*
+ * Only this function will be called explicitly by clients
+ * Register the specified client port (fcoei/fcoet)
+ */
+fcoe_port_t *
+fcoe_register_client(fcoe_client_t *client)
+{
+ fcoe_mac_t *mac;
+ fcoe_port_t *eport;
+
+ ASSERT(mutex_owned(&fcoe_global_ss->ss_ioctl_mutex));
+
+ /*
+ * We will not come here, when someone is changing ss_mac_list,
+ * so it's safe to go through ss_mac_list.
+ */
+ for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
+ mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
+ if (strcmp(client->ect_channel_name, mac->fm_link_name)
+ == 0) {
+ break;
+ }
+ }
+
+ if (mac == NULL) {
+ FCOE_LOG(0, "can't find the MAC you want to bind");
+ return (NULL);
+ }
+
+ if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
+ FCOE_LOG(0, "the MAC you want to bind is bound already");
+ return (NULL);
+ }
+
+ atomic_or_32(&mac->fm_flags, FCOE_MAC_FLAG_BOUND);
+ bcopy(client, &mac->fm_client, sizeof (fcoe_client_t));
+
+ /*
+ * fcoe_port_t initialization
+ */
+ eport = &mac->fm_eport;
+ eport->eport_flags = client->ect_eport_flags | EPORT_FLAG_MAC_IN_USE;
+ eport->eport_fcoe_private = mac;
+ eport->eport_client_private = client->ect_client_port_struct;
+ eport->eport_max_fc_frame_size = 2136;
+ eport->eport_tx_frame = fcoe_tx_frame;
+ eport->eport_alloc_frame = fcoe_allocate_frame;
+ eport->eport_release_frame = fcoe_release_frame;
+ eport->eport_alloc_netb = fcoe_alloc_netb;
+ eport->eport_free_netb = fcoe_free_netb;
+ eport->eport_deregister_client = fcoe_deregister_client;
+ eport->eport_ctl = fcoe_ctl;
+ eport->eport_set_mac_address = fcoe_mac_set_address;
+
+ return (eport);
+}
+
+/*
+ * The following routines will be called through vectors in fcoe_port_t
+ */
+
+/*
+ * Deregister fcoet/fcoei modules, client should make sure the port is in
+ * offline status already
+ */
+static void
+fcoe_deregister_client(fcoe_port_t *eport)
+{
+ fcoe_mac_t *mac = EPORT2MAC(eport);
+
+ ASSERT(mutex_owned(&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
+ * is already in offline status so no frame will be received or sent
+ * any more
+ */
+ while (mac->fm_frm_cnt > 0) {
+ delay(10);
+ }
+
+ atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND);
+}
+
+/* ARGSUSED */
+static int
+fcoe_ctl(fcoe_port_t *eport, int cmd, void *arg)
+{
+ fcoe_mac_t *mac = EPORT2MAC(eport);
+
+ switch (cmd) {
+ case FCOE_CMD_PORT_ONLINE:
+ /*
+ * client ask us to online, so it's safe to post event
+ * and data up
+ */
+ if (fcoe_enable_callback(mac) == FCOE_FAILURE) {
+ return (FCOE_FAILURE);
+ }
+ mac->fm_state = FCOE_MAC_STATE_ONLINE;
+ if (mac->fm_link_state == FCOE_MAC_LINK_STATE_UP)
+ (void) ddi_taskq_dispatch(
+ fcoe_global_ss->ss_watchdog_taskq,
+ fcoe_mac_notify_link_up, mac, DDI_SLEEP);
+ break;
+ case FCOE_CMD_PORT_OFFLINE:
+ if (fcoe_disable_callback(mac) == FCOE_FAILURE) {
+ return (FCOE_FAILURE);
+ }
+ mac->fm_state = FCOE_MAC_STATE_OFFLINE;
+ // in case there are threads waiting
+ mutex_enter(&mac->fm_mutex);
+ cv_broadcast(&mac->fm_tx_cv);
+ mutex_exit(&mac->fm_mutex);
+ break;
+ default:
+ FCOE_LOG("fcoe", "fcoe_ctl, unsupported cmd %x", cmd);
+ break;
+ }
+
+ return (FCOE_SUCCESS);
+}
+
+/*
+ * Transmit the specified frame to the link
+ */
+static void
+fcoe_tx_frame(fcoe_frame_t *frm)
+{
+ mblk_t *ret_mblk = NULL;
+ fcoe_mac_t *mac = FRM2MAC(frm);
+ mac_tx_cookie_t ret_cookie;
+
+ fcoe_fill_frame_headers(frm);
+ fcoe_fill_frame_tailers(frm);
+
+tx_frame:
+ ret_cookie = mac_tx(mac->fm_cli_handle, FRM2MBLK(frm), 0,
+ MAC_TX_NO_ENQUEUE, &ret_mblk);
+ if (ret_cookie != NULL) {
+ mutex_enter(&mac->fm_mutex);
+ (void) cv_timedwait(&mac->fm_tx_cv, &mac->fm_mutex,
+ ddi_get_lbolt() + drv_usectohz(100000));
+ mutex_exit(&mac->fm_mutex);
+
+ if (mac->fm_state == FCOE_MAC_STATE_OFFLINE) {
+ /*
+ * we are doing offline, so just tell the upper that
+ * this is finished, the cmd will be aborted soon.
+ */
+ fcoe_free_netb(ret_mblk);
+ } else {
+ goto tx_frame;
+ }
+ }
+
+ /*
+ * MAC driver will release the mblk of the frame
+ * We need only release the frame itself
+ */
+ mutex_enter(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
+ list_insert_tail(&FRM2MAC(frm)->fm_ss->ss_pfrm_list,
+ FRM2FMI(frm));
+ mac->fm_frm_cnt ++;
+ if (FRM2MAC(frm)->fm_ss->ss_flags & SS_FLAG_DOG_WAITING) {
+ cv_signal(&FRM2MAC(frm)->fm_ss->ss_watch_cv);
+ }
+ mutex_exit(&FRM2MAC(frm)->fm_ss->ss_watch_mutex);
+}
+
+/*
+ * Consider cache allocation in the future
+ */
+void
+fcoe_release_frame(fcoe_frame_t *frame)
+{
+ kmem_free(frame, frame->frm_alloc_size);
+}
+
+static void *
+fcoe_alloc_netb(fcoe_port_t *eport, uint32_t fc_frame_size, uint8_t **ppfc)
+{
+ mblk_t *mp;
+
+ mp = fcoe_get_mblk(eport->eport_fcoe_private,
+ fc_frame_size + PADDING_SIZE);
+ if (mp != NULL) {
+ *ppfc = mp->b_rptr + PADDING_HEADER_SIZE;
+ }
+
+ return (mp);
+}
+
+static void
+fcoe_free_netb(void *netb)
+{
+ freeb((mblk_t *)netb);
+}
+
+fcoe_frame_t *
+fcoe_allocate_frame(fcoe_port_t *eport, uint32_t fc_frame_size, void *xmp)
+{
+ fcoe_frame_t *frm;
+ fcoe_i_frame_t *fmi;
+ mblk_t *mp = xmp;
+ uint32_t alloc_size;
+ uint32_t raw_frame_size;
+
+ if (fc_frame_size > 2136) {
+ FCOE_LOG("fcoe", "fcoe_allocate_frame %d > 2136",
+ fc_frame_size);
+ return (NULL);
+ }
+
+ if (mp == NULL) {
+ /*
+ * We are allocating solicited frame now
+ */
+ raw_frame_size = PADDING_SIZE + fc_frame_size;
+ mp = fcoe_get_mblk(EPORT2MAC(eport), raw_frame_size);
+ if (mp == NULL) {
+ return (NULL);
+ }
+ }
+
+ alloc_size = sizeof (fcoe_frame_t) + sizeof (fcoe_i_frame_t) +
+ EPORT2MAC(eport)->fm_client.ect_private_frame_struct_size;
+
+ /*
+ * fcoe_frame_t initialization
+ */
+ frm = (fcoe_frame_t *)kmem_alloc(alloc_size, KM_SLEEP);
+ frm->frm_alloc_size = alloc_size;
+ frm->frm_fc_frame_size = fc_frame_size;
+ frm->frm_payload_size = fc_frame_size -
+ sizeof (fcoe_fc_frame_header_t);
+ frm->frm_fcoe_private = sizeof (fcoe_frame_t) + (uint8_t *)frm;
+ frm->frm_client_private = sizeof (fcoe_i_frame_t) +
+ (uint8_t *)frm->frm_fcoe_private;
+ frm->frm_flags = 0;
+ frm->frm_eport = eport;
+ frm->frm_netb = mp;
+
+ /*
+ * fcoe_i_frame_t initialization
+ */
+ fmi = FRM2FMI(frm);
+ fmi->fmi_frame = frm;
+ fmi->fmi_mac = EPORT2MAC(eport);
+ fmi->fmi_efh = (void *)mp->b_rptr;
+
+ fmi->fmi_ffh = (fcoe_frame_header_t *)
+ (sizeof (struct ether_header) + (uint8_t *)fmi->fmi_efh);
+
+ fmi->fmi_fc_frame = sizeof (fcoe_frame_header_t) +
+ (uint8_t *)fmi->fmi_ffh;
+ fmi->fmi_fft = (fcoe_frame_tailer_t *)
+ (fc_frame_size + (uint8_t *)fmi->fmi_fc_frame);
+
+ /*
+ * Continue to initialize fcoe_frame_t
+ */
+ frm->frm_hdr = (fcoe_fc_frame_header_t *)fmi->fmi_fc_frame;
+ frm->frm_ofh1 = NULL;
+ frm->frm_ofh2 = NULL;
+ frm->frm_fc_frame = (uint8_t *)frm->frm_hdr;
+ frm->frm_payload = sizeof (fcoe_fc_frame_header_t) +
+ (uint8_t *)frm->frm_fc_frame;
+ return (frm);
+}
+
+/*
+ * Sub routines called by interface functions
+ */
+
+/*
+ * According to spec, fill EthernetII frame header, FCoE frame header
+ * VLAN (not included for now)
+ */
+static void
+fcoe_fill_frame_headers(fcoe_frame_t *frm)
+{
+ fcoe_i_frame_t *fmi = FRM2FMI(frm);
+
+ /*
+ * Initialize ethernet frame header
+ */
+ bcopy(FRM2MAC(frm)->fm_current_addr, &fmi->fmi_efh->ether_shost,
+ ETHERADDRL);
+ bcopy(frm->frm_eport->eport_efh_dst,
+ &fmi->fmi_efh->ether_dhost, ETHERADDRL);
+ fmi->fmi_efh->ether_type = htons(ETHERTYPE_FCOE);
+
+ /*
+ * Initialize FCoE frame header
+ */
+ bzero(fmi->fmi_ffh, sizeof (fcoe_frame_header_t));
+ FCOE_ENCAPS_VER(fmi->fmi_ffh, FCOE_VER);
+ /* set to SOFi3 for the first frame of a sequence */
+ if (FRM_SEQ_CNT(frm) == 0) {
+ FCOE_V2B_1(0x2E, fmi->fmi_ffh->ffh_sof);
+ } else {
+ FCOE_V2B_1(0x36, fmi->fmi_ffh->ffh_sof);
+ }
+}
+
+/*
+ * According to spec, fill FCOE frame tailer including CRC
+ * VLAN (not included for now)
+ */
+static void
+fcoe_fill_frame_tailers(fcoe_frame_t *frm)
+{
+ uint32_t crc;
+
+ /*
+ * Initialize FCoE frame tailer
+ * CRC is not big endian, can't use macro V2B
+ */
+ CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size,
+ (uint32_t)~0, crc32_table);
+ FRM2FMI(frm)->fmi_fft->fft_crc[0] = 0xFF & (~crc);
+ FRM2FMI(frm)->fmi_fft->fft_crc[1] = 0xFF & (~crc >> 8);
+ FRM2FMI(frm)->fmi_fft->fft_crc[2] = 0xFF & (~crc >> 16);
+ FRM2FMI(frm)->fmi_fft->fft_crc[3] = 0xFF & (~crc >> 24);
+ if (FRM_F_CTL(frm) & 0x080000) {
+ FCOE_V2B_1(0x42, FRM2FMI(frm)->fmi_fft->fft_eof);
+ } else {
+ FCOE_V2B_1(0x41, FRM2FMI(frm)->fmi_fft->fft_eof);
+ }
+
+ FRM2FMI(frm)->fmi_fft->fft_resvd[0] = 0;
+ FRM2FMI(frm)->fmi_fft->fft_resvd[1] = 0;
+ FRM2FMI(frm)->fmi_fft->fft_resvd[2] = 0;
+}
+
+void
+fcoe_mac_notify_link_up(void *arg)
+{
+ fcoe_mac_t *mac = (fcoe_mac_t *)arg;
+
+ ASSERT(mac->fm_flags & FCOE_MAC_FLAG_BOUND);
+
+ mac->fm_client.ect_port_event(&mac->fm_eport,
+ FCOE_NOTIFY_EPORT_LINK_UP);
+}
+void
+fcoe_mac_notify_link_down(void *arg)
+{
+ fcoe_mac_t *mac = (fcoe_mac_t *)arg;
+
+ if (mac->fm_flags & FCOE_MAC_FLAG_BOUND) {
+ mac->fm_client.ect_port_event(&mac->fm_eport,
+ FCOE_NOTIFY_EPORT_LINK_DOWN);
+ }
+}
+
+int
+fcoe_create_port(dev_info_t *parent, fcoe_mac_t *mac, int is_target)
+{
+ int rval = 0;
+ dev_info_t *child = NULL;
+ char *mac_name = mac->fm_link_name;
+ char *devname = is_target ? FCOET_DRIVER_NAME : FCOEI_DRIVER_NAME;
+
+ ndi_devi_alloc_sleep(parent, devname, DEVI_PSEUDO_NODEID, &child);
+ if (child == NULL) {
+ FCOE_LOG("fcoe", "fail to create new devinfo");
+ return (NDI_FAILURE);
+ }
+
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, child,
+ "mac_name", mac_name) != DDI_PROP_SUCCESS) {
+ FCOE_LOG("fcoe",
+ "fcoe%d: prop_update port mac name failed for mac %s",
+ ddi_get_instance(parent), mac_name);
+ (void) ndi_devi_free(child);
+ return (NDI_FAILURE);
+ }
+
+ rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
+ if (rval != NDI_SUCCESS) {
+ FCOE_LOG("fcoe", "fcoe%d: online_driver failed for mac %s",
+ ddi_get_instance(parent), mac->fm_link_name);
+ return (NDI_FAILURE);
+ }
+ mac->fm_client_dev = child;
+
+ return (rval);
+}
+
+int
+fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, uint8_t *mac_name)
+{
+ int rval = 0;
+ fcoe_mac_t *mac;
+
+ mac = fcoe_lookup_mac_by_name(mac_name);
+ if (mac == NULL) {
+ fcoeio->fcoeio_status = FCOEIOE_MAC_NOT_FOUND;
+ return (EINVAL);
+ }
+
+ 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);
+
+ rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE);
+ if (rval != NDI_SUCCESS) {
+ FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed",
+ ddi_get_instance(parent),
+ ddi_get_name(mac->fm_client_dev));
+ atomic_or_32(&mac->fm_eport.eport_flags,
+ EPORT_FLAG_MAC_IN_USE);
+
+ fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE;
+ return (EBUSY);
+ }
+ (void) fcoe_close_mac(mac);
+ fcoe_destroy_mac(mac);
+ return (0);
+}
diff --git a/usr/src/uts/common/io/fcoe/fcoe_fc.h b/usr/src/uts/common/io/fcoe/fcoe_fc.h
new file mode 100644
index 0000000000..8fbbe52936
--- /dev/null
+++ b/usr/src/uts/common/io/fcoe/fcoe_fc.h
@@ -0,0 +1,47 @@
+/*
+ * 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 _FCOE_FC_H_
+#define _FCOE_FC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+extern void fcoe_release_frame(fcoe_frame_t *);
+extern fcoe_frame_t *fcoe_allocate_frame(fcoe_port_t *, uint32_t, void *);
+extern void fcoe_mac_notify_link_up(void *);
+extern void fcoe_mac_notify_link_down(void *);
+extern int fcoe_create_port(dev_info_t *, fcoe_mac_t *, int);
+extern int fcoe_delete_port(dev_info_t *, fcoeio_t *, uint8_t *);
+
+#endif /* _KERNEL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOE_FC_H_ */
diff --git a/usr/src/uts/common/sys/ethernet.h b/usr/src/uts/common/sys/ethernet.h
index 97531e917c..eb1b686540 100644
--- a/usr/src/uts/common/sys/ethernet.h
+++ b/usr/src/uts/common/sys/ethernet.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +30,6 @@
#ifndef _SYS_ETHERNET_H
#define _SYS_ETHERNET_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -94,6 +92,7 @@ struct ether_vlan_extinfo {
#define ETHERTYPE_PPPOES (0x8864) /* PPPoE Session Stage */
#define ETHERTYPE_EAPOL (0x888e) /* EAPOL protocol */
#define ETHERTYPE_RSN_PREAUTH (0x88c7) /* RSN PRE-Authentication */
+#define ETHERTYPE_FCOE (0x8906) /* FCoE */
#define ETHERTYPE_MAX (0xffff) /* Max valid ethernet type */
/*
diff --git a/usr/src/uts/common/sys/fcoe/fcoe_common.h b/usr/src/uts/common/sys/fcoe/fcoe_common.h
new file mode 100644
index 0000000000..bad3c5a133
--- /dev/null
+++ b/usr/src/uts/common/sys/fcoe/fcoe_common.h
@@ -0,0 +1,349 @@
+/*
+ * 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 _FCOE_COMMON_H_
+#define _FCOE_COMMON_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _KERNEL
+
+/*
+ * Interface return value
+ */
+#define FCOE_SUCCESS 0
+#define FCOE_FAILURE -1
+#define FCOE_BUSY -2
+#define FCOE_NOT_SUPPORTED -3
+#define FCOE_BAD_FRAME -4
+
+/*
+ * FCOE port speed
+ */
+#define FCOE_PORT_SPEED_1G 1000000000
+#define FCOE_PORT_SPEED_10G 10000000000
+
+/*
+ * FC Frame header size: 24 bytes
+ */
+#define FCFH_SIZE (sizeof (fcoe_fc_frame_header_t))
+
+/*
+ * FLOGI
+ */
+#define FLOGI_REQ_PAYLOAD_SIZE 116
+#define FLOGI_ACC_PAYLOAD_SIZE 116
+
+/*
+ * Minimum MTU size
+ */
+#define FCOE_MIN_MTU_SIZE 2500
+
+/*
+ * 24 byte FC frame header
+ * For all data structures that have endian problems, we will use only
+ * one type: uint8_t. We need associate the data structure pointer with
+ * one buffer directly.
+ */
+typedef struct fcoe_fc_frame_header {
+ uint8_t hdr_r_ctl[1];
+ uint8_t hdr_d_id[3];
+
+ uint8_t hdr_cs_ctl[1];
+ uint8_t hdr_s_id[3];
+
+ uint8_t hdr_type[1];
+ uint8_t hdr_f_ctl[3];
+
+ uint8_t hdr_seq_id[1];
+ uint8_t hdr_df_ctl[1];
+ uint8_t hdr_seq_cnt[2];
+
+ uint8_t hdr_oxid[2];
+ uint8_t hdr_rxid[2];
+
+ uint8_t hdr_param[4];
+} fcoe_fc_frame_header_t;
+
+/*
+ * Solicited frame: allocted by FCOET/FOCEI, free-ed by FCOE
+ * Unsolicited frame: allocated by FCOE, free-ed by FCOET/FCOEI
+ */
+struct fcoe_port;
+typedef struct fcoe_frame {
+ uint32_t frm_flags;
+ void *frm_netb;
+ fcoe_fc_frame_header_t *frm_hdr;
+ uint8_t *frm_ofh1;
+ uint8_t *frm_ofh2;
+ uint8_t *frm_fc_frame;
+ uint8_t *frm_payload;
+ uint32_t frm_fc_frame_size;
+ uint32_t frm_payload_size;
+ uint32_t frm_alloc_size;
+ struct fcoe_port *frm_eport;
+ void *frm_fcoe_private;
+ void *frm_client_private;
+} fcoe_frame_t;
+
+/*
+ * FCOE HBA
+ */
+typedef struct fcoe_port {
+ uint32_t eport_flags;
+ void *eport_fcoe_private;
+ void *eport_client_private;
+ uint8_t eport_portwwn[8];
+ uint8_t eport_nodewwn[8];
+ uint32_t eport_max_fc_frame_size;
+ 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);
+ void (*eport_release_frame)(fcoe_frame_t *frame);
+ void *(*eport_alloc_netb)(struct fcoe_port *eport,
+ uint32_t this_fc_frame_size, uint8_t **ppfc);
+ void (*eport_free_netb)(void *netb);
+ void (*eport_deregister_client)(struct fcoe_port *eport);
+ int (*eport_ctl)(struct fcoe_port *eport,
+ int cmd, void *arg);
+ int (*eport_set_mac_address)(struct fcoe_port *eport,
+ uint8_t *addr, boolean_t fc_assigned);
+} fcoe_port_t;
+
+/*
+ * FCOE only supports two kinds of topology: direct P2P, fabric P2P.
+ */
+#define EPORT_FLAG_IS_DIRECT_P2P 0x01
+#define EPORT_FLAG_TGT_MODE 0x02
+#define EPORT_FLAG_INI_MODE 0x04
+#define EPORT_FLAG_MAC_IN_USE 0x08
+
+#define FCOE_NOTIFY_EPORT_LINK_UP 0x01
+#define FCOE_NOTIFY_EPORT_LINK_DOWN 0x02
+#define FCOE_NOTIFY_EPORT_ADDR_CHG 0x03
+
+#define FCOE_PORT_CTL_CMDS 0x3000
+#define FCOE_CMD_PORT_ONLINE (FCOE_PORT_CTL_CMDS | 0x01)
+#define FCOE_CMD_PORT_OFFLINE (FCOE_PORT_CTL_CMDS | 0x02)
+
+typedef struct fcoe_client {
+ uint32_t ect_eport_flags;
+ uint32_t ect_max_fc_frame_size;
+ uint32_t ect_private_frame_struct_size;
+ char ect_channel_name[32];
+ void *ect_client_port_struct;
+ void (*ect_rx_frame)(fcoe_frame_t *frame);
+ void (*ect_port_event)(fcoe_port_t *eport, uint32_t event);
+ void (*ect_release_sol_frame)(fcoe_frame_t *frame);
+} fcoe_client_t;
+
+/*
+ * Define common-used conversion or calculation macros
+ */
+#define FCOE_V2B_1(x_v, x_b) \
+ { \
+ ((uint8_t *)(x_b))[0] = 0xFF & (x_v); \
+ }
+
+#define FCOE_V2B_2(x_v, x_b) \
+ { \
+ ((uint8_t *)(x_b))[1] = 0xFF & (x_v); \
+ ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 8); \
+ }
+
+#define FCOE_V2B_3(x_v, x_b) \
+ { \
+ ((uint8_t *)(x_b))[2] = 0xFF & (x_v); \
+ ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 8); \
+ ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 16); \
+ }
+
+#define FCOE_V2B_4(x_v, x_b) \
+ { \
+ ((uint8_t *)(x_b))[3] = 0xFF & (x_v); \
+ ((uint8_t *)(x_b))[2] = 0xFF & ((x_v) >> 8); \
+ ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 16); \
+ ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 24); \
+ }
+
+#define FCOE_V2B_8(x_v, x_b) \
+ { \
+ ((uint8_t *)(x_b))[7] = 0xFF & (x_v); \
+ ((uint8_t *)(x_b))[6] = 0xFF & ((x_v) >> 8); \
+ ((uint8_t *)(x_b))[5] = 0xFF & ((x_v) >> 16); \
+ ((uint8_t *)(x_b))[4] = 0xFF & ((x_v) >> 24); \
+ ((uint8_t *)(x_b))[3] = 0xFF & ((x_v) >> 32); \
+ ((uint8_t *)(x_b))[2] = 0xFF & ((x_v) >> 40); \
+ ((uint8_t *)(x_b))[1] = 0xFF & ((x_v) >> 48); \
+ ((uint8_t *)(x_b))[0] = 0xFF & ((x_v) >> 56); \
+ }
+
+#define FCOE_B2V_1(x_b) \
+ ((((uint8_t *)(x_b))[0]) & 0xFF)
+
+#define FCOE_B2V_2(x_b) \
+ ((((uint8_t *)(x_b))[1] | ((uint8_t *)(x_b))[0] << 8) & 0xFFFF)
+
+#define FCOE_B2V_3(x_b) \
+ ((((uint8_t *)(x_b))[2] | ((uint8_t *)(x_b))[1] << 8 | \
+ ((uint8_t *)(x_b))[0] << 16) & 0xFFFFFF)
+
+#define FCOE_B2V_4(x_b) \
+ ((((uint8_t *)(x_b))[3] | ((uint8_t *)(x_b))[2] << 8 | \
+ ((uint8_t *)(x_b))[1] << 16 | \
+ ((uint8_t *)(x_b))[0] << 24) & 0xFFFFFFFF)
+
+#define FCOE_B2V_8(x_b) \
+ ((((uint8_t *)(x_b))[7] | ((uint8_t *)(x_b))[6] << 8 | \
+ ((uint8_t *)(x_b))[5] << 16 | \
+ ((uint8_t *)(x_b))[4] << 24 | \
+ ((uint8_t *)(x_b))[3] << 32 | \
+ ((uint8_t *)(x_b))[2] << 40 | \
+ ((uint8_t *)(x_b))[1] << 48 | \
+ ((uint8_t *)(x_b))[0] << 56) & 0xFFFFFFFFFFFFFFFF)
+
+/*
+ * Get FC frame header's element
+ */
+#define FRM_R_CTL(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_r_ctl))
+#define FRM_D_ID(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_d_id))
+#define FRM_S_ID(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_s_id))
+#define FRM_TYPE(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_type))
+#define FRM_F_CTL(x_frm) (FCOE_B2V_3((x_frm)->frm_hdr->hdr_f_ctl))
+#define FRM_SEQ_ID(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_seq_id))
+#define FRM_DF_CTL(x_frm) (FCOE_B2V_1((x_frm)->frm_hdr->hdr_df_ctl))
+#define FRM_SEQ_CNT(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_seq_cnt))
+#define FRM_OXID(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_oxid))
+#define FRM_RXID(x_frm) (FCOE_B2V_2((x_frm)->frm_hdr->hdr_rxid))
+#define FRM_PARAM(x_frm) (FCOE_B2V_4((x_frm)->frm_hdr->hdr_param))
+
+/*
+ * Set FC frame header's element
+ */
+#define FFM_R_CTL(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_r_ctl)
+#define FFM_D_ID(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_d_id)
+#define FFM_S_ID(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_s_id)
+#define FFM_TYPE(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_type)
+#define FFM_F_CTL(x_v, x_frm) FCOE_V2B_3((x_v), (x_frm)->frm_hdr->hdr_f_ctl)
+#define FFM_SEQ_ID(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_seq_id)
+#define FFM_DF_CTL(x_v, x_frm) FCOE_V2B_1((x_v), (x_frm)->frm_hdr->hdr_df_ctl)
+#define FFM_SEQ_CNT(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_seq_cnt)
+#define FFM_OXID(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_oxid)
+#define FFM_RXID(x_v, x_frm) FCOE_V2B_2((x_v), (x_frm)->frm_hdr->hdr_rxid)
+#define FFM_PARAM(x_v, x_frm) FCOE_V2B_4((x_v), (x_frm)->frm_hdr->hdr_param)
+
+/*
+ * frame header checking
+ */
+#define FRM_IS_LAST_FRAME(x_frm) (FRM_F_CTL(x_frm) & (1 << 19))
+
+/*
+ * FCOET/FCOEI will only call this fcoe function explicitly, all others
+ * should be called through vectors in struct fcoe_port.
+ * FCOE client call this to register one port to FCOE, FCOE need initialize
+ * and return the corresponding fcoe_port.
+ */
+extern fcoe_port_t *fcoe_register_client(fcoe_client_t *client);
+
+#define EPORT_CLT_TYPE(eport) \
+ (((eport)->eport_flags & EPORT_FLAG_INI_MODE) ? \
+ FCOE_CLIENT_INITIATOR : FCOE_CLIENT_TARGET)
+
+#define FCOE_SET_DEFAULT_OUI(x_oui) \
+ (x_oui)[0] = 0x0e; (x_oui)[1] = 0xfc; (x_oui)[2] = 0x00;
+#define FCOE_SET_DEFAULT_FPORT_ADDR(x_addr) \
+ FCOE_SET_DEFAULT_OUI(x_addr) \
+ (x_addr)[3] = 0xff; (x_addr)[4] = 0xff; (x_addr)[5] = 0xfe;
+
+/*
+ * FC payload size
+ */
+#define FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE 2048
+#define FCOE_MIN_FCP_DATA_PAYLOAD_SIZE 1024
+
+typedef struct fcoe_fcp_cmnd {
+ uint8_t ffc_lun[8];
+ uint8_t ffc_ref_num[1];
+
+ /*
+ * least 3 bits
+ */
+ uint8_t ffc_attribute[1];
+
+ /*
+ * Magnagement flags
+ */
+ uint8_t ffc_management_flags[1];
+
+ /*
+ * additional cdb len and read/write flag
+ */
+ uint8_t ffc_addlen_rdwr[1];
+
+ uint8_t ffc_cdb[16];
+ uint8_t ffc_fcp_dl[4];
+} fcoe_fcp_cmnd_t;
+
+typedef struct fcoe_fcp_rsp {
+ uint8_t ffr_rsvd[8];
+
+ /*
+ * see SAM-4
+ */
+ uint8_t ffr_retry_delay_timer[2];
+ uint8_t ffr_flags[1];
+ uint8_t ffr_scsi_status[1];
+ uint8_t ffr_resid[4];
+ uint8_t ffr_sns_len[4];
+ uint8_t ffr_rsp_len[4];
+ /*
+ * Followed by sense data when available
+ */
+} fcoe_fcp_rsp_t;
+
+typedef struct fcoe_fcp_xfer_rdy {
+ uint8_t fxr_data_ro[4];
+ uint8_t fxr_burst_len[4];
+ uint8_t fxr_rsvd[4];
+} fcoe_fcp_xfer_rdy_t;
+
+/*
+ * FCOE project global functions
+ */
+#define FCOE_SEC2TICK(x_sec) (drv_usectohz((x_sec) * 1000000))
+typedef void (*TQ_FUNC_P)(void *);
+extern void fcoe_trace(caddr_t ident, const char *fmt, ...);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOE_COMMON_H_ */
diff --git a/usr/src/uts/common/sys/fcoe/fcoeio.h b/usr/src/uts/common/sys/fcoe/fcoeio.h
new file mode 100644
index 0000000000..6d24a2673f
--- /dev/null
+++ b/usr/src/uts/common/sys/fcoe/fcoeio.h
@@ -0,0 +1,144 @@
+/*
+ * 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 _FCOEIO_H_
+#define _FCOEIO_H_
+
+#include <sys/ethernet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ioctl cmd definitions
+ */
+#define FCOEIO_CMD ('G'<< 8 | 2009)
+#define FCOEIO_SUB_CMD ('X' << 8)
+
+/*
+ * fcoe ioctl sub-command
+ */
+#define FCOEIO_CREATE_FCOE_PORT (FCOEIO_SUB_CMD + 0x01)
+#define FCOEIO_DELETE_FCOE_PORT (FCOEIO_SUB_CMD + 0x02)
+#define FCOEIO_GET_FCOE_PORT_LIST (FCOEIO_SUB_CMD + 0x03)
+
+/*
+ * define common-used constants
+ */
+#define FCOE_MAX_MAC_NAME_LEN 32
+
+/*
+ * fcoeio_xfer definitions
+ */
+#define FCOEIO_XFER_NONE 0x00
+#define FCOEIO_XFER_READ 0x01
+#define FCOEIO_XFER_WRITE 0x02
+#define FCOEIO_XFER_RW (FCOEIO_XFER_READ | FCOEIO_XFER_WRITE)
+
+/*
+ * fcoeio_errno definitions
+ */
+typedef enum {
+ FCOEIOE_INVAL_ARG = 5,
+ FCOEIOE_BUSY,
+ FCOEIOE_ALREADY,
+ FCOEIOE_PWWN_CONFLICTED,
+ FCOEIOE_NWWN_CONFLICTED,
+ FCOEIOE_CREATE_MAC,
+ FCOEIOE_OPEN_MAC,
+ FCOEIOE_CREATE_PORT,
+ FCOEIOE_NEED_JUMBO_FRAME,
+ FCOEIOE_MAC_NOT_FOUND,
+ FCOEIOE_OFFLINE_FAILURE,
+ FCOEIOE_MORE_DATA,
+ FCOEIOE_VNIC_UNSUPPORT
+} fcoeio_stat_t;
+
+/* Biggest buffer length, can hold up to 1024 port instances */
+#define FCOEIO_MAX_BUF_LEN 0x10000
+
+typedef struct fcoeio {
+ uint16_t fcoeio_xfer; /* direction */
+ uint16_t fcoeio_cmd; /* sub command */
+ uint16_t fcoeio_flags; /* flags */
+ uint16_t fcoeio_cmd_flags; /* command specific flags */
+ uint32_t fcoeio_ilen; /* Input buffer length */
+ uint32_t fcoeio_olen; /* Output buffer length */
+ uint32_t fcoeio_alen; /* Auxillary buffer length */
+ fcoeio_stat_t fcoeio_status; /* FC internal error status */
+ uint64_t fcoeio_ibuf; /* Input buffer */
+ uint64_t fcoeio_obuf; /* Output buffer */
+ uint64_t fcoeio_abuf; /* Auxillary buffer */
+} fcoeio_t;
+
+/*
+ * Client port type
+ */
+typedef enum {
+ FCOE_CLIENT_INITIATOR = 0,
+ FCOE_CLIENT_TARGET
+} fcoe_cli_type_t;
+
+/*
+ * Command for FCOEIO_CREATE_FCOET_PORT
+ */
+#define FCOE_WWN_SIZE 8
+typedef struct fcoeio_create_port_param {
+ uchar_t fcp_pwwn[FCOE_WWN_SIZE];
+ uchar_t fcp_nwwn[FCOE_WWN_SIZE];
+ uint32_t fcp_nwwn_provided;
+ uint32_t fcp_pwwn_provided;
+ uint32_t fcp_force_promisc;
+ fcoe_cli_type_t fcp_port_type;
+ uchar_t fcp_mac_name[MAXLINKNAMELEN];
+} fcoeio_create_port_param_t;
+
+/*
+ * FCOE port instance
+ */
+typedef struct fcoe_port_instance {
+ uchar_t fpi_pwwn[FCOE_WWN_SIZE];
+ uchar_t fpi_mac_link_name[MAXLINKNAMELEN];
+ uint8_t fpi_mac_factory_addr[ETHERADDRL];
+ uint16_t fpi_mac_promisc;
+ uint8_t fpi_mac_current_addr[ETHERADDRL];
+ uint16_t fpi_rsvd1;
+ fcoe_cli_type_t fpi_port_type;
+ uint32_t fpi_mtu_size;
+} fcoe_port_instance_t;
+
+/*
+ * FCOE port instance list
+ */
+typedef struct fcoe_port_list {
+ uint64_t numPorts;
+ fcoe_port_instance_t ports[1];
+} fcoe_port_list_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FCOEIO_H_ */
diff --git a/usr/src/uts/common/sys/fct.h b/usr/src/uts/common/sys/fct.h
index 1808038963..514535afba 100644
--- a/usr/src/uts/common/sys/fct.h
+++ b/usr/src/uts/common/sys/fct.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.
*/
#ifndef _FCT_H
@@ -294,6 +294,7 @@ typedef struct fct_link_info {
#define PORT_SPEED_2G 2
#define PORT_SPEED_4G 4
#define PORT_SPEED_8G 8
+#define PORT_SPEED_10G 16
/*
* Abort commands
diff --git a/usr/src/uts/common/sys/stmf.h b/usr/src/uts/common/sys/stmf.h
index 940545b255..1159cc13b1 100644
--- a/usr/src/uts/common/sys/stmf.h
+++ b/usr/src/uts/common/sys/stmf.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.
*/
#ifndef _STMF_H
@@ -87,6 +87,7 @@ typedef struct stmf_data_buf {
#define DB_SEND_STATUS_GOOD 0x0004
#define DB_STATUS_GOOD_SENT 0x0008
#define DB_DONT_CACHE 0x0010
+#define DB_DONT_REUSE 0x0020
typedef struct scsi_task {
void *task_stmf_private;
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index 734bfd007c..8dc5f05120 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -333,6 +333,8 @@ DRV_KMODS += zyd
DRV_KMODS += stmf
DRV_KMODS += stmf_sbd
DRV_KMODS += fct
+DRV_KMODS += fcoe
+DRV_KMODS += fcoet
DRV_KMODS += qlt
DRV_KMODS += iscsit
DRV_KMODS += ncall nsctl sdbc nskern sv
diff --git a/usr/src/uts/intel/fcoe/Makefile b/usr/src/uts/intel/fcoe/Makefile
new file mode 100644
index 0000000000..3fda0d67d2
--- /dev/null
+++ b/usr/src/uts/intel/fcoe/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 fcoe driver
+
+#
+# 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 = fcoe
+OBJECTS = $(FCOE_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(FCOE_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/io/fcoe
+
+#
+# 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
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+LDFLAGS += -dy -Ndrv/mac
+INC_PATH += -I$(UTSBASE)/common/io/fcoe
+
+#
+# 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/intel/fcoet/Makefile b/usr/src/uts/intel/fcoet/Makefile
new file mode 100644
index 0000000000..ca049c7c3a
--- /dev/null
+++ b/usr/src/uts/intel/fcoet/Makefile
@@ -0,0 +1,86 @@
+#
+# 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
+#
+# uts/intel/fcoet/Makefile
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# This makefile drives the production of the fcoet driver for COMSTAR.
+#
+
+#
+# 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 = fcoet
+OBJECTS = $(FCOET_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(FCOET_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include ../Makefile.$(ARCHDIR)
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Overrides and depends_on
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+LDFLAGS += -dy -Ndrv/stmf -Ndrv/fct -Ndrv/fcoe
+INC_PATH += -I$(UTSBASE)/common/io/comstar/port/fcoet
+
+#
+# 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 f226ccda05..df11c813cc 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -295,6 +295,8 @@ DRV_KMODS += dmd
DRV_KMODS += stmf
DRV_KMODS += stmf_sbd
DRV_KMODS += fct
+DRV_KMODS += fcoe
+DRV_KMODS += fcoet
DRV_KMODS += qlt
DRV_KMODS += iscsit
DRV_KMODS += ncall nsctl sdbc nskern sv
diff --git a/usr/src/uts/sparc/fcoe/Makefile b/usr/src/uts/sparc/fcoe/Makefile
new file mode 100644
index 0000000000..72e55c644e
--- /dev/null
+++ b/usr/src/uts/sparc/fcoe/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 fcoe driver.
+
+#
+# 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 = fcoe
+OBJECTS = $(FCOE_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(FCOE_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR = $(UTSBASE)/common/io/fcoe
+
+#
+# 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
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+LDFLAGS += -dy -Ndrv/mac
+INC_PATH += -I$(UTSBASE)/common/io/fcoe
+
+#
+# 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/fcoet/Makefile b/usr/src/uts/sparc/fcoet/Makefile
new file mode 100644
index 0000000000..049893b085
--- /dev/null
+++ b/usr/src/uts/sparc/fcoet/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
+#
+# uts/sparc/fcoet/Makefile
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# This makefile drives the production of the fcoet driver for COMSTAR.
+#
+
+#
+# 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 = fcoet
+OBJECTS = $(FCOET_OBJS:%=$(OBJS_DIR)/%)
+LINTS = $(FCOET_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include ../Makefile.$(ARCHDIR)
+
+#
+# Define targets
+#
+ALL_TARGET = $(BINARY)
+LINT_TARGET = $(MODULE).lint
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+
+#
+# Overrides and depends_on
+#
+MODSTUBS_DIR = $(OBJS_DIR)
+LDFLAGS += -dy -Ndrv/stmf -Ndrv/fct -Ndrv/fcoe
+INC_PATH += -I$(UTSBASE)/common/io/comstar/port/fcoet
+
+# 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