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